在阅读了类的结构、属性、方法交换、对象关联之后,我们可以看到,这些所有的所有操作都与object
相关,在我们开发过程中,我们也可以看到很多类都继承自NSObject
,比如:UIResponder
,UINavigationItem
等。
我们接下来看看NSObject
的代码有些什么内容呢?
首先是NSObject
协议,包含了NSObject
相关的抽象,都是我们平常会使用到的一些方法。
@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
NSObject
协议定义了Objective-C
对象公用的相关方法,我们大多时候都会将NSObject
作为我们的基类, 其实我们也可以使用NSObject
自己实现一个基类,现在我们跟着NSObject
协议去看看NSObject
怎么实现的基类。
首先我们看看对象相关的方法。
+ (id)self {
return (id)self;
}
- (id)self {
return self;
}
+ (Class)class {
return self;
}
- (Class)class {
return object_getClass(self);
}
+ (Class)superclass {
return self->superclass;
}
- (Class)superclass {
return [self class]->superclass;
}
这些方法方法我们可以看出来都是获取对象自己及父类class
相关的实现。我们先定义一个SubClass
来输出这几个方法获取的结果。
@interface SubClass : NSObject
@end
@implementation SubClass
@end
然后初始化SubClass
并打印相关方法的结果,可以获得如下结果。
[obj self] : <SubClass: 0x600001a980a0>
[obj class] : SubClass
[SubClass self] : SubClass
[SubClass class] : SubClass
[obj superclass] : NSObject
[SubClass superclass] : NSObject
从这些方法中我们可以得出结果:
[obj self]
获取当前对象,查找当前对象的引用地址;
[obj class]
获取当前对象的引用类型,获取当前类的的引用类型;
[SubClass self]
和``[SubClass class] `都是获取当前的引用类型,查找当前类的引用类型对象;
[obj superclass]
和[SubClass superclass]
都是获取父类的引用类型。
我们再看看我们常用来判断子类
、父类
、是否为当前类的成员对象的方法,由于这些方法十分简单,我就将对应的描述放到注释里面。
// 判断当前类是否等于目标类
+ (BOOL)isMemberOfClass:(Class)cls {
return object_getClass((id)self) == cls;
}
// 判断当前对象的引用类型是否是目标类的成员对象
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
// 遍历判断当前类是否是目标类的子类
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
// 判断当前类是否是目标类的子类成员对象
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
// 判断当前类是否是目标类的子类
+ (BOOL)isSubclassOfClass:(Class)cls {
for (Class tcls = self; tcls; tcls = tcls->superclass) {
if (tcls == cls) return YES;
}
return NO;
}
// 判断当前类是否是目标对象的父类
+ (BOOL)isAncestorOfObject:(NSObject *)obj {
for (Class tcls = [obj class]; tcls; tcls = tcls->superclass) {
if (tcls == self) return YES;
}
return NO;
}
我们有时会在代码中判断某个类是否实现某一个协议会使用到conformsToProtocol
去判断是否实现了某个协议,会循环遍历父类,然后调用class_conformsToProtocol
去判断是否实现了这个协议。
+ (BOOL)conformsToProtocol:(Protocol *)protocol {
if (!protocol) return NO;
for (Class tcls = self; tcls; tcls = tcls->superclass) {
if (class_conformsToProtocol(tcls, protocol)) return YES;
}
return NO;
}
- (BOOL)conformsToProtocol:(Protocol *)protocol {
if (!protocol) return NO;
for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
if (class_conformsToProtocol(tcls, protocol)) return YES;
}
return NO;
}
BOOL class_conformsToProtocol(Class cls, Protocol *proto_gen)
{
protocol_t *proto = newprotocol(proto_gen);
if (!cls) return NO;
if (!proto_gen) return NO;
mutex_locker_t lock(runtimeLock);
checkIsKnownClass(cls);
assert(cls->isRealized());
for (const auto& proto_ref : cls->data()->protocols) {
protocol_t *p = remapProtocol(proto_ref);
if (p == proto || protocol_conformsToProtocol_nolock(p, proto)) {
return YES;
}
}
return NO;
}
我们经常会在使用代理的时候看到一段代码:
if ([_delegate respondsToSelector:@selector(xxx:)]{
[_delegate xxx];
}
然后我们再看看NSObject
里面respondsToSelector
默认实现是什么样的呢?
+ (BOOL)instancesRespondToSelector:(SEL)sel {
if (!sel) return NO;
return class_respondsToSelector(self, sel);
}
+ (BOOL)respondsToSelector:(SEL)sel {
if (!sel) return NO;
return class_respondsToSelector_inst(object_getClass(self), sel, self);
}
- (BOOL)respondsToSelector:(SEL)sel {
if (!sel) return NO;
return class_respondsToSelector_inst([self class], sel, self);
}
调用respondsToSelector
会转发给class_respondsToSelector_inst
方法去查找这个Selector
的IMP
来判断当前类是否实现xxx
方法,instancesRespondToSelector
也是通过class_respondsToSelector
转发给class_respondsToSelector_inst
方法。
// inst is an instance of cls or a subclass thereof, or nil if none is known.
// Non-nil inst is faster in some cases. See lookUpImpOrForward() for details.
bool class_respondsToSelector_inst(Class cls, SEL sel, id inst)
{
IMP imp;
if (!sel || !cls) return NO;
// Avoids +initialize because it historically did so.
// We're not returning a callable IMP anyway.
imp = lookUpImpOrNil(cls, sel, inst,
NO/*initialize*/, YES/*cache*/, YES/*resolver*/);
return bool(imp);
}
对于performSelector
这个用来执行方法的函数我们也经常回事用到,这个函数主要调用objc_msgSend
进行消息转发,具体实现在objc_msgSend
部分再详细学习。
+ (id)performSelector:(SEL)sel {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL))objc_msgSend)((id)self, sel);
}
+ (id)performSelector:(SEL)sel withObject:(id)obj {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id))objc_msgSend)((id)self, sel, obj);
}
+ (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id, id))objc_msgSend)((id)self, sel, obj1, obj2);
}
- (id)performSelector:(SEL)sel {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL))objc_msgSend)(self, sel);
}
- (id)performSelector:(SEL)sel withObject:(id)obj {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id))objc_msgSend)(self, sel, obj);
}
- (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id, id))objc_msgSend)(self, sel, obj1, obj2);
}
我们经常会使用到isEqualXX
来对比两个对象是否相等,为什么不用isEqual
或则==
呢,我们来看看isEqual
的实现,从实现来看我们可以发现方法是对比两个对象是否相等,而对于NSString
或者NSArray
的成员对象来说,我们需要判断它们的值是否相等而不是地址是否相等,否则很容易出现地址一致而值不一致的问题。
+ (BOOL)isEqual:(id)obj {
return obj == (id)self;
}
- (BOOL)isEqual:(id)obj {
return obj == self;
}
我们经常会使用hash判断两个对象是否相等,在NSObject
里面默认返回当前类的地址hash
值。
+ (NSUInteger)hash {
return _objc_rootHash(self);
}
- (NSUInteger)hash {
return _objc_rootHash(self);
}
uintptr_t
_objc_rootHash(id obj)
{
return (uintptr_t)obj;
}
我们经常都会使用NSLog(@"obj : %@", obj);
来输出某个对象查看相关的属性,我们可以通过重写description
方法来自定义对象的输出。
// Replaced by CF (returns an NSString)
+ (NSString *)description {
return nil;
}
// Replaced by CF (returns an NSString)
- (NSString *)description {
return nil;
}
+ (NSString *)debugDescription {
return [self description];
}
- (NSString *)debugDescription {
return [self description];
}
至此,NSObject
协议的默认实现基本上就介绍完了,NSObject
剩下的大多数方法都是作为父类方法,用于后面方法实现,就不再一一介绍了。
更好的阅读体验可以参考个人网站:https://zevwings.com
网友评论