ios开发 之 NSObject详解

 NSObject是大部分Objective-C类继承体系的根类。这个类遵循NSObject协议,提供了一些通用的方法,对象通过继承NSObject,可以从其中继承访问运行时的接口,并让对象具备Objective-C对象的基本能力。下面我们就详细的介绍NSObject。

原文地址:http://blog.csdn.net/zeng_zhiming/article/details/70225456


一、使用详解

首先创建两个测试类

创建ZMPerson继承NSObject
[objc]  view plain  copy
  1. //===============ZMPerson.h文件==================  
  2.   
  3. #import <Foundation/Foundation.h>  
  4.   
  5. @interface ZMPerson : NSObject  
  6.   
  7. @property (nonatomiccopyNSString *name; //!< 姓名  
  8. @property (nonatomic, assign) NSInteger age; //!< 年龄  
  9.   
  10. /** 穿衣 */  
  11. - (void)dressing;  
  12.   
  13. /** 吃东西 */  
  14. - (void)eating;  
  15.   
  16. /** 睡觉 */  
  17. - (void)sleeping;  
  18.   
  19. /** 跑 */  
  20. - (void)running;  
  21.   
  22. @end  
  23.   
  24. //===========ZMPerson.m文件==============  
  25.   
  26. #import "ZMPerson.h"  
  27.   
  28. @implementation ZMPerson  
  29.   
  30. /** 穿衣 */  
  31. - (void)dressing  
  32. {  
  33. NSLog(@"-->Person dressing");  
  34. }  
  35.   
  36. /** 吃东西 */  
  37. - (void)eating  
  38. {  
  39. NSLog(@"-->Person eating");  
  40. }  
  41.   
  42. /** 睡觉 */  
  43. - (void)sleeping  
  44. {  
  45. NSLog(@"-->Person sleeping");  
  46. }  
  47.   
  48. /** 跑 */  
  49. - (void)running  
  50. {  
  51. NSLog(@"-->Person running");  
  52. }  
  53.   
  54. @end  

创建ZMStudent继承ZMPerson
[objc]  view plain  copy
  1. //===============ZMStudent.h文件==================  
  2.   
  3. #import "ZMPerson.h"  
  4.   
  5. @interface ZMStudent : ZMPerson  
  6.   
  7. @property (nonatomicstrongNSString *school; //!< 学校  
  8. @property (nonatomicstrongNSString *grade; //!< 年级  
  9.   
  10. /** 写字 */  
  11. - (void)writing;  
  12.   
  13. /** 读书 */  
  14. - (void)readingWithText:(NSString *)text;  
  15.   
  16. /** 加法运算 */  
  17. - (NSNumber *)sumWithNum:(NSNumber *)num1 num2:(NSNumber *)num2;  
  18.   
  19. @end  
  20.   
  21. //===============ZMStudent.m文件==================  
  22.   
  23. #import "ZMStudent.h"  
  24.   
  25. @implementation ZMStudent  
  26.   
  27. /** 写字 */  
  28. - (void)writing  
  29. {  
  30. NSLog(@"-->Student writing");  
  31. }  
  32.   
  33. /** 读书 */  
  34. - (void)readingWithText:(NSString *)text  
  35. {  
  36. NSLog(@"-->Student reading:%@", text);  
  37. }  
  38.   
  39. /** 加法运算 */  
  40. - (NSNumber *)sumWithNum:(NSNumber *)num1 num2:(NSNumber *)num2;  
  41. {  
  42. return @([num1 floatValue] + [num2 floatValue]);  
  43. }  
  44.   
  45. @end  

1、加载及初始化类

[objc]  view plain  copy
  1. /** 运行时加载类或分类调用该方法, 每个类只会调用一次 */  
  2. + (void)load {  
  3.   
  4. }  
  5.   
  6. /** 类实例化使用前需要先初始化, 一个类调用一次, 如果子类没有实现该方法则会调用父类方法 */  
  7. + (void)initialize {  
  8.   
  9. }  
     `load`和`initialize`区别在于:`load`是只要类所在文件被引用就会被调用,而`initialize`是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有`load`调用;但即使类文件被引用进来,但是没有使用,那么`initialize`也不会被调用;`load`每个类只会调用一次,`initialize`也只调用一次,但是如果子类没有实现`initialize`方法则会调用父类的方法,因此作为父类的`initialize`方法可能会调用多次。

2、分配内存空间及初始化对象

[objc]  view plain  copy
  1. ZMStudent *student = [ZMStudent new];  
  2.   
  3. ZMStudent *student2 = [[ZMStudent alloc] init];  
  4.   
  5. ZMStudent *student3 = [[ZMStudent allocWithZone:nil] init];  
      创建新对象时,首先调用`alloc`为对象分配内存空间,再调用`init`初始化对象,如`[[NSObject alloc] init]`;而`new`方法先给新对象分配空间然后初始化对象,因此`[NSObject new]`等同于`[[NSObject alloc] init]`;关于`allocWithZone`方法,官方文档解释该方法的参数是被忽略的,正确的做法是传nil或者NULL参数给它。

3、给对象发送消息(执行方法)

(1)直接调用

[objc]  view plain  copy
  1. // 调用无参无返回值方法  
  2. [student running];  
  3. // 调用有参无返回值方法  
  4. [student readingWithText:@"Hello World!"];  
  5. // 调用有参有返回值方法  
  6. NSNumber *sum = [student sumWithNum:@(2) num2:@(3)];  
      我们通常都采用这种直接调用的方式,给对象发消息执行方法。这种方式调用编译时会自动校验方法、参数、返回值是否正确。因此我们必须在头文件中声明方法的使用。

(2)使用`performSelector`执行

[objc]  view plain  copy
  1. // 先判断对象是否能调用方法,再执行调用方法  
  2. if ([student respondsToSelector:@selector(running)]) {  
  3. // 调用无参无返回值方法  
  4. [student performSelector:@selector(running)];  
  5. }  
  6. if ([student respondsToSelector:@selector(readingWithText:)]) {  
  7. // 调用有参无返回值方法  
  8. [student performSelector:@selector(readingWithText:) withObject:@"Hello World"];  
  9. }  
  10. if ([student respondsToSelector:@selector(sumWithNum:num2:)]) {  
  11. // 调用有参有返回值方法  
  12. NSNumber *sum = [student performSelector:@selector(sumWithNum:num2:) withObject:@(2) withObject:@(8)];  
  13. }  
        使用`performSelector:`是运行时系统负责去找方法,在编译时候不做任何校验;因此在使用时必须先使用`respondsToSelector:`检查对象是否能调用方法,否则可能出现运行崩溃。`performSelector:`常用于调用运行时添加的方法,即编译时不存在,但是运行时候存在的方法。另外需要注意的是`performSelector:`系统提供最多接受两个参数的方法,而且参数和返回都是`id`类型,并不支持基础数据类型(如:int, float等)。

(3)使用IMP指针调用

[objc]  view plain  copy
  1. // 创建SEL  
  2. SEL runSel = @selector(running);  
  3. SEL readSel = NSSelectorFromString(@"readingWithText:");  
  4. SEL sumSel = NSSelectorFromString(@"sumWithNum:num2:");  
  5.   
  6. // 调用无参无返回值方法  
  7. IMP rumImp = [student methodForSelector:runSel];  
  8. void (*runFunc)(idSEL) = (voidvoid *)rumImp;  
  9. runFunc(student, runSel);  
  10.   
  11. // 调用有参无返回值方法  
  12. IMP readImp = [[student class] instanceMethodForSelector:readSel];  
  13. void (*speakFunc)(idSELNSString *) = (voidvoid *)readImp;  
  14. speakFunc(student, readSel, @"Hello World");  
  15.   
  16. // 调用有参有返回值方法  
  17. IMP sumImp = [student methodForSelector:sumSel];  
  18. NSNumber *(*sumFunc)(idSELNSNumber *, NSNumber *) = (voidvoid *)sumImp;  
  19. NSNumber *sum3 = sumFunc(student, sumSel, @(6), @(6));  
      `SEL` 是方法的索引。IMP是函数指针,指向方法的地址。`SEL`与`IMP`是一一对应的关系,因此我们可以通过修改对应关系达到运行时方法交换的目的。
创建`SEL`对象两种方法:
1、使用`@selector()`创建
2、使用`NSSelectorFromString()`创建
获取方法`IMP`指针两种方法:
1、`- (IMP)methodForSelector:(SEL)aSelector;` 实例方法
2、`+ (IMP)instanceMethodForSelector:(SEL)aSelector;` 类方法

4、复制对象

[objc]  view plain  copy
  1. // 两个源数组  
  2. NSArray *sourceArrayI = [NSArray arrayWithObjects:@"I"@"I", nil nil];  
  3. NSMutableArray *sourceArrayM = [NSMutableArray arrayWithObjects:@"M"@"M", nil nil];  
  4.   
  5. // 两个copy  
  6. NSArray *copyArrayI = [sourceArrayI copy];  
  7. NSArray *copyArrayM = [sourceArrayM copy];  
  8.   
  9. // 两个mutableCopy  
  10. NSMutableArray *mutableArrayI = [sourceArrayI mutableCopy];  
  11. NSMutableArray *mutableArrayM = [sourceArrayM mutableCopy];  
     `copy`拷贝为不可变对象,`mutableCopy`拷贝为可变变量,`copy`和`mutableCopy`都可理解为复制了一个新对象。虽然`copy`对静态对象只是引用计数加1,但是并不影响我们对复制前后的对象进行使用。需要注意的是对于容器对象而言,这两个方法只是复制了容器本身,对容器中包含的对象只是简单的指针引用,并没有深层复制。

5、获取Class

[objc]  view plain  copy
  1. // 获取类  
  2. Class curClass1 = [student class];  
  3. Class curClass2 = [ZMStudent class];  
  4.   
  5. // 获取父类  
  6. Class supClass1 = [student superclass];  
  7. Class supClass2 = [ZMStudent superclass];  

6、判断方法

[objc]  view plain  copy
  1. // 初始化对象  
  2. ZMPerson *person = [ZMPerson new];  
  3. ZMStudent *student = [ZMStudent new];  
  4. ZMStudent *student2 = student;  
  5.   
  6. // 判断对象是否继承NSObject  
  7. if ([student isProxy]) {  
  8. NSLog(@"student对象是继承NSObject类");  
  9. }  
  10.   
  11. // 判断两个对象是否相等  
  12. if ([student isEqual:student2]) {  
  13. NSLog(@"student对象与student2对象相等");  
  14. }  
  15.   
  16. // 判断对象是否是指定类  
  17. if ([person isKindOfClass:[ZMPerson class]]) {  
  18. NSLog(@"person对象是ZMPerson类");  
  19. }  
  20.   
  21. // 判断对象是否是指定类或子类  
  22. if ([student isKindOfClass:[ZMPerson class]]) {  
  23. NSLog(@"student对象是ZMPerson类的子类");  
  24. }  
  25.   
  26. // 判断是否是另一个类的子类  
  27. if ([ZMStudent isSubclassOfClass:[ZMPerson class]]) {  
  28. NSLog(@"ZMStudent类是ZMPerson类的子类");  
  29. }  
  30.   
  31. // 判判断对象是否遵从协议  
  32. if ([student conformsToProtocol:@protocol(NSObject)]) {  
  33. NSLog(@"student对象遵循NSObject协议");  
  34. }  
  35.   
  36. // 判断类是否遵从给定的协议  
  37. if ([ZMStudent conformsToProtocol:@protocol(NSObject)]) {  
  38. NSLog(@"ZMStudent类遵循NSObject协议");  
  39. }  
  40.   
  41. // 判断对象是否能够调用给定的方法  
  42. if ([student respondsToSelector:@selector(running)]) {  
  43. NSLog(@"student对象可以调用‘running’方法");  
  44. }  
  45.   
  46. // 判断实例是否能够调用给定的方法  
  47. if ([ZMStudent instancesRespondToSelector:@selector(running)]) {  
  48. NSLog(@"ZMStudent类可以调用‘running’方法");  
  49. }  

二、NSObject.h详解

[objc]  view plain  copy
  1. //  
  2. // NSObject.h  
  3. // ZMHeaderFile  
  4. //  
  5. // Created by ZengZhiming on 2017/4/17.  
  6. // Copyright © 2017年 菜鸟基地. All rights reserved.  
  7. //  
  8. // 详解 NSObject.h  
  9. // Version iOS 10.3  
  10. //  
  11.   
  12. #ifndef _OBJC_NSOBJECT_H_  
  13. #define _OBJC_NSOBJECT_H_  
  14.   
  15. #if __OBJC__  
  16.   
  17. #include <objc/objc.h>  
  18. #include <objc/NSObjCRuntime.h>  
  19.   
  20. @class NSString, NSMethodSignature, NSInvocation;  
  21.   
  22. #pragma mark - 协议部分  
  23.   
  24. @protocol NSObject  
  25.   
  26. /** 判断两个对象是否相等, 如相等返回YES, 否则返回NO */  
  27. - (BOOL)isEqual:(id)object;  
  28. /** 获取对象hash值, 两对象相等hash值也相等 */  
  29. @property (readonly) NSUInteger hash;  
  30.   
  31. /** 获取对象的父类 */  
  32. @property (readonly) Class superclass;  
  33. /** 获取当前对象的类 */  
  34. - (Class)class OBJC_SWIFT_UNAVAILABLE("use 'type(of: anObject)' instead");  
  35. /** 获取当前对象 */  
  36. - (instancetype)self;  
  37.   
  38. /** 发送指定的消息给对象, 返回消息执行结果(相当于方法调用) */  
  39. - (id)performSelector:(SEL)aSelector;  
  40. /** 发送带一个参数的消息给对象, 返回消息执行结果(相当于方法调用) */  
  41. - (id)performSelector:(SEL)aSelector withObject:(id)object;  
  42. /** 发送带两个参数的消息给对象, 返回消息执行结果(相当于方法调用) */  
  43. - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;  
  44.   
  45. /** 判断对象是否继承NSObject */  
  46. - (BOOL)isProxy;  
  47.   
  48. /** 判断对象是否是给定类或给定类子类的实例 */  
  49. - (BOOL)isKindOfClass:(Class)aClass;  
  50. /** 判断对象是否是给定类的实例 */  
  51. - (BOOL)isMemberOfClass:(Class)aClass;  
  52. /** 判断对象是否遵从给定的协议 */  
  53. - (BOOL)conformsToProtocol:(Protocol *)aProtocol;  
  54.   
  55. /** 判断对象是否能够调用给定的方法 */  
  56. - (BOOL)respondsToSelector:(SEL)aSelector;  
  57.   
  58. /** 对象引用计数加1, 在MRC下使用 */  
  59. - (instancetype)retain OBJC_ARC_UNAVAILABLE;  
  60. /** 对象引用计数减1, 在MRC下使用 */  
  61. - (oneway void)release OBJC_ARC_UNAVAILABLE;  
  62. /** 对象引用计数以推迟方式自动减1, 在MRC下使用 */  
  63. - (instancetype)autorelease OBJC_ARC_UNAVAILABLE;  
  64. /** 获取对象引用计数, 在MRC下使用 */  
  65. - (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;  
  66. /** 获取对象存储空间, 在MRC下使用 */  
  67. - (struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;  
  68.   
  69. /** 获取对象描述信息 */  
  70. @property (readonlycopyNSString *description;  
  71. @optional  
  72. /** 获取对象在调试器中的描述信息 */  
  73. @property (readonlycopyNSString *debugDescription;  
  74.   
  75. @end  
  76.   
  77. #pragma mark - 类部分  
  78.   
  79. OBJC_AVAILABLE(10.02.09.01.0)  
  80. OBJC_ROOT_CLASS  
  81. OBJC_EXPORT  
  82. @interface NSObject <NSObject> {  
  83. Class isa OBJC_ISA_AVAILABILITY;  
  84. }  
  85.   
  86. /** 运行时加载类或分类调用该方法, 每个类只会调用一次 */  
  87. + (void)load;  
  88. /** 类实例化使用前需要先初始化, 一个类调用一次, 如果子类没有实现该方法则会调用父类方法 */  
  89. + (void)initialize;  
  90. /** 初始化对象 */  
  91. - (instancetype)init  
  92. #if NS_ENFORCE_NSOBJECT_DESIGNATED_INITIALIZER  
  93. NS_DESIGNATED_INITIALIZER  
  94. #endif  
  95. ;  
  96.   
  97. /** 为新对象分配内存空间并初始化, 等于[[NSObject alloc] init] */  
  98. + (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  
  99. /** 为新对象分配内存空间, 参数传nil */  
  100. + (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  
  101. /** 为新对象分配内存空间 */  
  102. + (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");  
  103. /** 释放对象, 当对象的引用计数为0时会调用此方法 */  
  104. - (void)dealloc OBJC_SWIFT_UNAVAILABLE("use 'deinit' to define a de-initializer");  
  105. /** 垃圾回收器调用此方法前处理它所使用的内存。 */  
  106. - (void)finalize OBJC_DEPRECATED("Objective-C garbage collection is no longer supported");  
  107.   
  108. /** 复制为不可变对象 */  
  109. - (id)copy;  
  110. /** 复制为可变对象 */  
  111. - (id)mutableCopy;  
  112.   
  113. /** 在指定的内存空间上复制为不可变对象, 在MRC下使用 */  
  114. + (id)copyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;  
  115. /** 在指定的内存空间上复制为可变对象, 在MRC下使用 */  
  116. + (id)mutableCopyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;  
  117.   
  118. /** 判断实例是否能够调用给定的方法 */  
  119. + (BOOL)instancesRespondToSelector:(SEL)aSelector;  
  120. /** 判断类是否遵从给定的协议 */  
  121. + (BOOL)conformsToProtocol:(Protocol *)protocol;  
  122. /** 获取指向方法实现IMP的指针 */  
  123. - (IMP)methodForSelector:(SEL)aSelector;  
  124. /** 获取指向实例方法实现IMP的指针 */  
  125. + (IMP)instanceMethodForSelector:(SEL)aSelector;  
  126. /** 找不到函数实现的将调用此方法抛出异常 */  
  127. - (void)doesNotRecognizeSelector:(SEL)aSelector;  
  128.   
  129. /** 返回消息被第一个转发的对象, 对象没有找到SEL的IML时就会执行调用该方法 */  
  130. - (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.52.09.01.0);  
  131. /** methodSignatureForSelector:返回不为nil则调用该方法, 可以重写该方法将SEL转发给另一个对象 */  
  132. - (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");  
  133. /** 获取方法签名, 对象没有找到SEL的IML时就会执行调用该方法, 可以重写该方法抛出一个函数的签名,再由forwardInvocation:去执行 */  
  134. - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");  
  135.   
  136. /** 获取实例方法签名 */  
  137. + (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");  
  138.   
  139. /** 允许弱引用标量, 对于所有allowsWeakReference方法返回NO的类都绝对不能使用__weak修饰符 */  
  140. - (BOOL)allowsWeakReference UNAVAILABLE_ATTRIBUTE;  
  141. /** 保留弱引用变量, 在使用__weak修饰符的变量时, 当被赋值对象的retainWeakReference方法返回NO的情况下, 该变量将使用“nil” */  
  142. - (BOOL)retainWeakReference UNAVAILABLE_ATTRIBUTE;  
  143.   
  144. /** 判断是否是另一个类的子类 */  
  145. + (BOOL)isSubclassOfClass:(Class)aClass;  
  146.   
  147. /** 动态解析一个类方法 */  
  148. + (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.52.09.01.0);  
  149. /** 动态解析一个实例方法, 对象没有找到SEL的IML时就会执行调用该方法, 可以重写该方法给对象添加所需的SEL */  
  150. + (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.52.09.01.0);  
  151.   
  152. /** 获取对象hash值, 两对象相等hash值也相等*/  
  153. + (NSUInteger)hash;  
  154. /** 获取对象的父类 */  
  155. + (Class)superclass;  
  156. /** 获取类 */  
  157. + (Class)class OBJC_SWIFT_UNAVAILABLE("use 'aClass.self' instead");  
  158. /** 获取对象描述信息 */  
  159. + (NSString *)description;  
  160. /** 获取对象在调试器中的描述信息 */  
  161. + (NSString *)debugDescription;  
  162.   
  163. @end  
  164.   
  165. #endif  
  166.   
  167. #endif  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值