iOS 基礎篇 - 《NSObject對象詳解》

NSObject對象簡介

NSObject是大部分Objective-C類繼承體系的根類。這個類遵循NSObject協議,提供了一些通用的方法,對象通過繼承NSObject,可以從其中繼承訪問運行時的接口,并讓對象具備Objective-C對象的基本能力。偷懶了??原文地址

1、加載及初始化類


/** import導入類或分類時調用該方法, 整個生命周期內都只執行一次而已 */
+ (void)load {} 

/** 每次調用類時調用一次, 如果子類沒有實現該方法則會調用父類方法 */
+ (void)initialize {}

loadinitialize區別在于:
load是只要類所在文件被引用就會被調用。(import就會調用
initialize是在類或者其子類的第一個方法被調用前調用。但是如果子類沒有實現initialize方法則會調用父類的方法,因此作為父類的initialize方法可能會調用多次。(調用對象的第一個方法前如alloc)

2、分配內存空間及初始化對象

ZMStudent *student = [ZMStudent new];  //常用
ZMStudent *student2 = [[ZMStudent alloc] init];  //常用
ZMStudent *student3 = [[ZMStudent allocWithZone:nil] init];  //不常用

創建新對象時,首先調用alloc為對象分配內存空間,再調用init初始化對象,如[[NSObject alloc] init][NSObject new]等同于[[NSObject alloc] init];關于allocWithZone方法,官方文檔解釋該方法的參數是被忽略的,正確的做法是傳nil或者NULL參數給它。

3、給對象發送消息(執行方法)

(1)直接調用(最常用)

// 調用無參無返回值方法  
[student running];  
// 調用有參無返回值方法  
[student readingWithText:@"Hello World!"];  
// 調用有參有返回值方法  
NSNumber *sum = [student sumWithNum:@(2) num2:@(3)];  

我們通常都采用這種直接調用的方式,給對象發消息執行方法。這種方式調用編譯時會自動校驗方法、參數、返回值是否正確。因此我們必須在頭文件中聲明方法的使用。

(2)使用performSelector執行(常用)

// 先判斷對象是否能調用方法,再執行調用方法  
if ([student respondsToSelector:@selector(running)]) {  
// 調用無參無返回值方法  
[student performSelector:@selector(running)];  
}  
if ([student respondsToSelector:@selector(readingWithText:)]) {  
// 調用有參無返回值方法  
[student performSelector:@selector(readingWithText:) withObject:@"Hello World"];  
}  
if ([student respondsToSelector:@selector(sumWithNum:num2:)]) {  
// 調用有參有返回值方法  
NSNumber *sum = [student performSelector:@selector(sumWithNum:num2:) withObject:@(2) withObject:@(8)];  
}  

使用performSelector:是運行時系統負責去找方法,在編譯時候不做任何校驗;因此在使用時必須先使用respondsToSelector:檢查對象是否能調用方法,否則可能出現運行崩潰。performSelector:常用于調用運行時添加的方法,即編譯時不存在,但是運行時候存在的方法。另外需要注意的是performSelector:系統提供最多接受兩個參數的方法,而且參數和返回都是id類型,并不支持基礎數據類型(如:int, float等)。

(3)使用IMP指針調用(少用)

// 創建SEL  
SEL runSel = @selector(running);  
SEL readSel = NSSelectorFromString(@"readingWithText:");  
SEL sumSel = NSSelectorFromString(@"sumWithNum:num2:");  
  
// 調用無參無返回值方法  
IMP rumImp = [student methodForSelector:runSel];  
void (*runFunc)(id, SEL) = (voidvoid *)rumImp;  
runFunc(student, runSel);  
  
// 調用有參無返回值方法  
IMP readImp = [[student class] instanceMethodForSelector:readSel];  
void (*speakFunc)(id, SEL, NSString *) = (voidvoid *)readImp;  
speakFunc(student, readSel, @"Hello World");  
  
// 調用有參有返回值方法  
IMP sumImp = [student methodForSelector:sumSel];  
NSNumber *(*sumFunc)(id, SEL, NSNumber *, NSNumber *) = (voidvoid *)sumImp;  
NSNumber *sum3 = sumFunc(student, sumSel, @(6), @(6));  

SEL 是方法的索引。IMP是函數指針,指向方法的地址。SELIMP是一一對應的關系,因此我們可以通過修改對應關系達到運行時方法交換的目的。
創建SEL對象兩種方法:
1、使用@selector()創建
2、使用NSSelectorFromString()創建
獲取方法IMP指針兩種方法:
1、- (IMP)methodForSelector:(SEL)aSelector; 實例方法指針
2、+ (IMP)instanceMethodForSelector:(SEL)aSelector; 類方法指針

4、復制對象

// 兩個源數組  
NSArray *sourceArrayI = [NSArray arrayWithObjects:@"I", @"I", nil nil];  
NSMutableArray *sourceArrayM = [NSMutableArray arrayWithObjects:@"M", @"M", nil nil];  
  
// 兩個copy  
NSArray *copyArrayI = [sourceArrayI copy];  
NSArray *copyArrayM = [sourceArrayM copy];  
  
// 兩個mutableCopy  
NSMutableArray *mutableArrayI = [sourceArrayI mutableCopy];  
NSMutableArray *mutableArrayM = [sourceArrayM mutableCopy]; 

1、一個對象使用copymutabelCopy方法可以創建對象的副本
copy - 需要先實現NSCoppying協議,創建的是不可變副本(如NSString、NSArray、NSDictionary
2、mutabelCopy - 需要先實現NSMutabelCopying協議,創建的是可變副本,(如NSMutabelString、NSMutabelArray、NSMutabelDictionary
深復制:內容拷貝,源對象和副本指向的是不同的兩個對象。源對象引用計數器不變,副本計數器設置為1
3、淺復制:指針拷貝,源對象和副本指向的是同一個對象。對象的引用計數器+1,其實相當于做了一次retain操作
4、只有不可變對象創建不可變副本(copy)才是淺拷貝,其他都是深拷貝

5、獲取Class

// 獲取類  
Class curClass1 = [student class];  //獲取對象的類
Class curClass2 = [ZMStudent class];  //獲取類的父類
// 獲取父類  
Class supClass1 = [student superclass];  
Class supClass2 = [ZMStudent superclass];  

6、判斷方法

// 初始化對象  
ZMPerson *person = [ZMPerson new];  
ZMStudent *student = [ZMStudent new];  
ZMStudent *student2 = student;  
  
// 判斷對象是否繼承NSObject  
if ([student isProxy]) {  
NSLog(@"student對象是繼承NSObject類");  
}  
  
// 判斷兩個對象是否相等  
if ([student isEqual:student2]) {  
NSLog(@"student對象與student2對象相等");  
}  
  
// 判斷對象是否是指定類  
if ([person isKindOfClass:[ZMPerson class]]) {  
NSLog(@"person對象是ZMPerson類");  
}  
  
// 判斷對象是否是指定類或子類  
if ([student isKindOfClass:[ZMPerson class]]) {  
NSLog(@"student對象是ZMPerson類的子類");  
}  
  
// 判斷是否是另一個類的子類  
if ([ZMStudent isSubclassOfClass:[ZMPerson class]]) {  
NSLog(@"ZMStudent類是ZMPerson類的子類");  
}  
  
// 判判斷對象是否遵從協議  
if ([student conformsToProtocol:@protocol(NSObject)]) {  
NSLog(@"student對象遵循NSObject協議");  
}  
  
// 判斷類是否遵從給定的協議  
if ([ZMStudent conformsToProtocol:@protocol(NSObject)]) {  
NSLog(@"ZMStudent類遵循NSObject協議");  
}  
  
// 判斷對象是否能夠調用給定的方法  
if ([student respondsToSelector:@selector(running)]) {  
NSLog(@"student對象可以調用‘running’方法");  
}  
  
// 判斷實例是否能夠調用給定的方法  
if ([ZMStudent instancesRespondToSelector:@selector(running)]) {  
NSLog(@"ZMStudent類可以調用‘running’方法");  
}  

NSObject.h詳解



//  
// NSObject.h  
// ZMHeaderFile  
//  
// Created by ZengZhiming on 2017/4/17.  
// Copyright ? 2017年 菜鳥基地. All rights reserved.  
//  
// 詳解 NSObject.h  
// Version iOS 10.3  
//  
  
#ifndef _OBJC_NSOBJECT_H_  
#define _OBJC_NSOBJECT_H_  
  
#if __OBJC__  
  
#include <objc/objc.h>  
#include <objc/NSObjCRuntime.h>  
  
@class NSString, NSMethodSignature, NSInvocation;  
  
#pragma mark - 協議部分  
  
@protocol NSObject  
  
/** 判斷兩個對象是否相等, 如相等返回YES, 否則返回NO */  
- (BOOL)isEqual:(id)object;  
/** 獲取對象hash值, 兩對象相等hash值也相等 */  
@property (readonly) NSUInteger hash;  
  
/** 獲取對象的父類 */  
@property (readonly) Class superclass;  
/** 獲取當前對象的類 */  
- (Class)class OBJC_SWIFT_UNAVAILABLE("use 'type(of: anObject)' instead");  
/** 獲取當前對象 */  
- (instancetype)self;  
  
/** 發送指定的消息給對象, 返回消息執行結果(相當于方法調用) */  
- (id)performSelector:(SEL)aSelector;  
/** 發送帶一個參數的消息給對象, 返回消息執行結果(相當于方法調用) */  
- (id)performSelector:(SEL)aSelector withObject:(id)object;  
/** 發送帶兩個參數的消息給對象, 返回消息執行結果(相當于方法調用) */  
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;  
  
/** 判斷對象是否繼承NSObject */  
- (BOOL)isProxy;  
  
/** 判斷對象是否是給定類或給定類子類的實例 */  
- (BOOL)isKindOfClass:(Class)aClass;  
/** 判斷對象是否是給定類的實例 */  
- (BOOL)isMemberOfClass:(Class)aClass;  
/** 判斷對象是否遵從給定的協議 */  
- (BOOL)conformsToProtocol:(Protocol *)aProtocol;  
  
/** 判斷對象是否能夠調用給定的方法 */  
- (BOOL)respondsToSelector:(SEL)aSelector;  
  
/** 對象引用計數加1, 在MRC下使用 */  
- (instancetype)retain OBJC_ARC_UNAVAILABLE;  
/** 對象引用計數減1, 在MRC下使用 */  
- (oneway void)release OBJC_ARC_UNAVAILABLE;  
/** 對象引用計數以推遲方式自動減1, 在MRC下使用 */  
- (instancetype)autorelease OBJC_ARC_UNAVAILABLE;  
/** 獲取對象引用計數, 在MRC下使用 */  
- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;  
/** 獲取對象存儲空間, 在MRC下使用 */  
- (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;  
  
/** 獲取對象描述信息 */  
@property (readonly, copy) NSString *description;  
@optional  
/** 獲取對象在調試器中的描述信息 */  
@property (readonly, copy) NSString *debugDescription;  
  
@end  
  
#pragma mark - 類部分  
  
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0)  
OBJC_ROOT_CLASS  
OBJC_EXPORT  
@interface NSObject <NSObject> {  
Class isa OBJC_ISA_AVAILABILITY;  
}  
  
/** 運行時加載類或分類調用該方法, 每個類只會調用一次 */  
+ (void)load;  
/** 類實例化使用前需要先初始化, 一個類調用一次, 如果子類沒有實現該方法則會調用父類方法 */  
+ (void)initialize;  
/** 初始化對象 */  
- (instancetype)init  
#if NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER  
NS_DESIGNATED_INITIALIZER  
#endif  
;  
  
/** 為新對象分配內存空間并初始化, 等于[[NSObject alloc] init] */  
+ (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  
/** 為新對象分配內存空間, 參數傳nil */  
+ (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  
/** 為新對象分配內存空間 */  
+ (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  
/** 釋放對象, 當對象的引用計數為0時會調用此方法 */  
- (void)dealloc OBJC_SWIFT_UNAVAILABLE("use 'deinit' to define a de-initializer");  
/** 垃圾回收器調用此方法前處理它所使用的內存。 */  
- (void)finalize OBJC_DEPRECATED("Objective-C garbage collection is no longer supported");  
  
/** 復制為不可變對象 */  
- (id)copy;  
/** 復制為可變對象 */  
- (id)mutableCopy;  
  
/** 在指定的內存空間上復制為不可變對象, 在MRC下使用 */  
+ (id)copyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;  
/** 在指定的內存空間上復制為可變對象, 在MRC下使用 */  
+ (id)mutableCopyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;  
  
/** 判斷實例是否能夠調用給定的方法 */  
+ (BOOL)instancesRespondToSelector:(SEL)aSelector;  
/** 判斷類是否遵從給定的協議 */  
+ (BOOL)conformsToProtocol:(Protocol *)protocol;  
/** 獲取指向方法實現IMP的指針 */  
- (IMP)methodForSelector:(SEL)aSelector;  
/** 獲取指向實例方法實現IMP的指針 */  
+ (IMP)instanceMethodForSelector:(SEL)aSelector;  
/** 找不到函數實現的將調用此方法拋出異常 */  
- (void)doesNotRecognizeSelector:(SEL)aSelector;  
  
/** 返回消息被第一個轉發的對象, 對象沒有找到SEL的IML時就會執行調用該方法 */  
- (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);  
/** methodSignatureForSelector:返回不為nil則調用該方法, 可以重寫該方法將SEL轉發給另一個對象 */  
- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");  
/** 獲取方法簽名, 對象沒有找到SEL的IML時就會執行調用該方法, 可以重寫該方法拋出一個函數的簽名,再由forwardInvocation:去執行 */  
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");  
  
/** 獲取實例方法簽名 */  
+ (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");  
  
/** 允許弱引用標量, 對于所有allowsWeakReference方法返回NO的類都絕對不能使用__weak修飾符 */  
- (BOOL)allowsWeakReference UNAVAILABLE_ATTRIBUTE;  
/** 保留弱引用變量, 在使用__weak修飾符的變量時, 當被賦值對象的retainWeakReference方法返回NO的情況下, 該變量將使用“nil” */  
- (BOOL)retainWeakReference UNAVAILABLE_ATTRIBUTE;  
  
/** 判斷是否是另一個類的子類 */  
+ (BOOL)isSubclassOfClass:(Class)aClass;  
  
/** 動態解析一個類方法 */  
+ (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);  
/** 動態解析一個實例方法, 對象沒有找到SEL的IML時就會執行調用該方法, 可以重寫該方法給對象添加所需的SEL */  
+ (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);  
  
/** 獲取對象hash值, 兩對象相等hash值也相等*/  
+ (NSUInteger)hash;  
/** 獲取對象的父類 */  
+ (Class)superclass;  
/** 獲取類 */  
+ (Class)class OBJC_SWIFT_UNAVAILABLE("use 'aClass.self' instead");  
/** 獲取對象描述信息 */  
+ (NSString *)description;  
/** 獲取對象在調試器中的描述信息 */  
+ (NSString *)debugDescription;  
  
@end  
  
#endif  
  
#endif  
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,732評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,214評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,781評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,588評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,315評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,699評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,698評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,882評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,441評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,189評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,388評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,933評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,613評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,023評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,310評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,112評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,334評論 2 377

推薦閱讀更多精彩內容

  • 轉至元數據結尾創建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數據起始第一章:isa和Class一....
    40c0490e5268閱讀 1,755評論 0 9
  • OC語言基礎 1.類與對象 類方法 OC的類方法只有2種:靜態方法和實例方法兩種 在OC中,只要方法聲明在@int...
    奇異果好補閱讀 4,310評論 0 11
  • 目錄 Objective-C Runtime到底是什么 Objective-C的元素認知 Runtime詳解 應用...
    Ryan___閱讀 1,948評論 1 3
  • 廣州 廣州夜宵主要分為大排檔、酒樓和小龍蝦。 大排檔主要代表店鋪為東海生鮮。東海生仙的招牌菜中的香口菜有炸傻鱔蟛蜞...
    mamao閱讀 430評論 0 0
  • 第一部分 「引」 「神龕」,是供奉神像或神主的小閣子。 今天這篇文章是關于陰陽師的。 關注《陰陽師》手游的人,可能...
    小郭hhhh閱讀 764評論 9 6