NSObject是大部分Objective-C类继承体系的根类。这个类遵循NSObject协议,提供了一些通用的方法,对象通过继承NSObject,可以从其中继承访问运行时的接口,并让对象具备Objective-C对象的基本能力。下面我们就详细的介绍NSObject。
原文地址:http://blog.csdn.net/zeng_zhiming/article/details/70225456
一、使用详解
首先创建两个测试类
创建ZMPerson继承NSObject
-
-
- #import <Foundation/Foundation.h>
-
- @interface ZMPerson : NSObject
-
- @property (nonatomic, copy) NSString *name;
- @property (nonatomic, assign) NSInteger age;
-
-
- - (void)dressing;
-
-
- - (void)eating;
-
-
- - (void)sleeping;
-
-
- - (void)running;
-
- @end
-
-
-
- #import "ZMPerson.h"
-
- @implementation ZMPerson
-
-
- - (void)dressing
- {
- NSLog(@"-->Person dressing");
- }
-
-
- - (void)eating
- {
- NSLog(@"-->Person eating");
- }
-
-
- - (void)sleeping
- {
- NSLog(@"-->Person sleeping");
- }
-
-
- - (void)running
- {
- NSLog(@"-->Person running");
- }
-
- @end
创建ZMStudent继承ZMPerson
-
-
- #import "ZMPerson.h"
-
- @interface ZMStudent : ZMPerson
-
- @property (nonatomic, strong) NSString *school;
- @property (nonatomic, strong) NSString *grade;
-
-
- - (void)writing;
-
-
- - (void)readingWithText:(NSString *)text;
-
-
- - (NSNumber *)sumWithNum:(NSNumber *)num1 num2:(NSNumber *)num2;
-
- @end
-
-
-
- #import "ZMStudent.h"
-
- @implementation ZMStudent
-
-
- - (void)writing
- {
- NSLog(@"-->Student writing");
- }
-
-
- - (void)readingWithText:(NSString *)text
- {
- NSLog(@"-->Student reading:%@", text);
- }
-
-
- - (NSNumber *)sumWithNum:(NSNumber *)num1 num2:(NSNumber *)num2;
- {
- return @([num1 floatValue] + [num2 floatValue]);
- }
-
- @end
1、加载及初始化类
-
- + (void)load {
-
- }
-
-
- + (void)initialize {
-
- }
`load`和`initialize`区别在于:`load`是只要类所在文件被引用就会被调用,而`initialize`是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有`load`调用;但即使类文件被引用进来,但是没有使用,那么`initialize`也不会被调用;`load`每个类只会调用一次,`initialize`也只调用一次,但是如果子类没有实现`initialize`方法则会调用父类的方法,因此作为父类的`initialize`方法可能会调用多次。
2、分配内存空间及初始化对象
- ZMStudent *student = [ZMStudent new];
-
- ZMStudent *student2 = [[ZMStudent alloc] init];
-
- ZMStudent *student3 = [[ZMStudent allocWithZone:nil] init];
创建新对象时,首先调用`alloc`为对象分配内存空间,再调用`init`初始化对象,如`[[NSObject alloc] init]`;而`new`方法先给新对象分配空间然后初始化对象,因此`[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 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是函数指针,指向方法的地址。`SEL`与`IMP`是一一对应的关系,因此我们可以通过修改对应关系达到运行时方法交换的目的。
创建`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];
-
-
- NSArray *copyArrayI = [sourceArrayI copy];
- NSArray *copyArrayM = [sourceArrayM copy];
-
-
- NSMutableArray *mutableArrayI = [sourceArrayI mutableCopy];
- NSMutableArray *mutableArrayM = [sourceArrayM mutableCopy];
`copy`拷贝为不可变对象,`mutableCopy`拷贝为可变变量,`copy`和`mutableCopy`都可理解为复制了一个新对象。虽然`copy`对静态对象只是引用计数加1,但是并不影响我们对复制前后的对象进行使用。需要注意的是对于容器对象而言,这两个方法只是复制了容器本身,对容器中包含的对象只是简单的指针引用,并没有深层复制。
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;
-
-
- 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详解
-
-
-
-
-
-
-
-
-
-
-
- #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
-
-
- - (BOOL)isEqual:(id)object;
-
- @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;
-
-
- - (BOOL)isProxy;
-
-
- - (BOOL)isKindOfClass:(Class)aClass;
-
- - (BOOL)isMemberOfClass:(Class)aClass;
-
- - (BOOL)conformsToProtocol:(Protocol *)aProtocol;
-
-
- - (BOOL)respondsToSelector:(SEL)aSelector;
-
-
- - (instancetype)retain OBJC_ARC_UNAVAILABLE;
-
- - (oneway void)release OBJC_ARC_UNAVAILABLE;
-
- - (instancetype)autorelease OBJC_ARC_UNAVAILABLE;
-
- - (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;
-
- - (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
- ;
-
-
- + (instancetype)new OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
-
- + (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
-
- + (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
-
- - (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;
-
-
- + (id)copyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;
-
- + (id)mutableCopyWithZone:(struct _NSZone *)zone OBJC_ARC_UNAVAILABLE;
-
-
- + (BOOL)instancesRespondToSelector:(SEL)aSelector;
-
- + (BOOL)conformsToProtocol:(Protocol *)protocol;
-
- - (IMP)methodForSelector:(SEL)aSelector;
-
- + (IMP)instanceMethodForSelector:(SEL)aSelector;
-
- - (void)doesNotRecognizeSelector:(SEL)aSelector;
-
-
- - (id)forwardingTargetForSelector:(SEL)aSelector OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
-
- - (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE("");
-
- - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");
-
-
- + (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");
-
-
- - (BOOL)allowsWeakReference UNAVAILABLE_ATTRIBUTE;
-
- - (BOOL)retainWeakReference UNAVAILABLE_ATTRIBUTE;
-
-
- + (BOOL)isSubclassOfClass:(Class)aClass;
-
-
- + (BOOL)resolveClassMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
-
- + (BOOL)resolveInstanceMethod:(SEL)sel OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0);
-
-
- + (NSUInteger)hash;
-
- + (Class)superclass;
-
- + (Class)class OBJC_SWIFT_UNAVAILABLE("use 'aClass.self' instead");
-
- + (NSString *)description;
-
- + (NSString *)debugDescription;
-
- @end
-
- #endif
-
- #endif