setter方法底层实现
声明一个类LKPerson,并添加属性
@interface LKPerson : NSObject
@property (nonatomic, copy) NSString *nickName_nocopy;
@property (atomic, copy) NSString *nickName_copy;
@property (nonatomic) NSString *nickName;
@property (atomic) NSString *nickName_no;
@property (nonatomic, strong) NSString *nickName_nostr;
@property (atomic, strong) NSString *nickName_str;
@end
@implementation LKPerson
@end
通过clang编译成c++文件,查看底层实现
clang -rewrite-objc main.m -o main.cpp
可以看到set和get方法
static NSString * _I_LKPerson_nickName_nocopy(LKPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LKPerson$_nickName_nocopy)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
static void _I_LKPerson_setNickName_nocopy_(LKPerson * self, SEL _cmd, NSString *nickName_nocopy) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct LKPerson, _nickName_nocopy), (id)nickName_nocopy, 0, 1); }
extern "C" __declspec(dllimport) id objc_getProperty(id, SEL, long, bool);
static NSString * _I_LKPerson_nickName_copy(LKPerson * self, SEL _cmd) { typedef NSString * _TYPE;
return (_TYPE)objc_getProperty(self, _cmd, __OFFSETOFIVAR__(struct LKPerson, _nickName_copy), 1); }
static void _I_LKPerson_setNickName_copy_(LKPerson * self, SEL _cmd, NSString *nickName_copy) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct LKPerson, _nickName_copy), (id)nickName_copy, 1, 1); }
static NSString * _I_LKPerson_nickName(LKPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LKPerson$_nickName)); }
static void _I_LKPerson_setNickName_(LKPerson * self, SEL _cmd, NSString *nickName) { (*(NSString **)((char *)self + OBJC_IVAR_$_LKPerson$_nickName)) = nickName; }
static NSString * _I_LKPerson_nickName_no(LKPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LKPerson$_nickName_no)); }
static void _I_LKPerson_setNickName_no_(LKPerson * self, SEL _cmd, NSString *nickName_no) { (*(NSString **)((char *)self + OBJC_IVAR_$_LKPerson$_nickName_no)) = nickName_no; }
static NSString * _I_LKPerson_nickName_nostr(LKPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LKPerson$_nickName_nostr)); }
static void _I_LKPerson_setNickName_nostr_(LKPerson * self, SEL _cmd, NSString *nickName_nostr) { (*(NSString **)((char *)self + OBJC_IVAR_$_LKPerson$_nickName_nostr)) = nickName_nostr; }
static NSString * _I_LKPerson_nickName_str(LKPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LKPerson$_nickName_str)); }
static void _I_LKPerson_setNickName_str_(LKPerson * self, SEL _cmd, NSString *nickName_str) { (*(NSString **)((char *)self + OBJC_IVAR_$_LKPerson$_nickName_str)) = nickName_str; }
可以看出,含有copy关键字的实现方式为objc_setProperty,而不包含copy关键字实现方式为内存偏移。
isKindOfClass和isMemberOfClass
查看isKindOfClass和isMemberOfClass底层实现源码
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
BOOL objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
if (slowpath(!obj)) return NO;
Class cls = obj->getIsa();
if (fastpath(!cls->hasCustomCore())) {
for (Class tcls = cls; tcls; tcls = tcls->getSuperclass()) {
if (tcls == otherClass) return YES;
}
return NO;
}
#endif
return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}
可以看出,类方法的isKindOfClass和isMemberOfClass,都是查找的元类,然后进行比较。实例方法都是查找类来进行比较。isKindOfClass和isMemberOfClass的区别在于,isKindOfClass会查找父类,而isMemberOfClass不会。
验证
BOOL reg1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
BOOL reg2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
BOOL reg3 = [(id)[LKPerson class] isKindOfClass:[LKPerson class]];
BOOL reg4 = [(id)[LKPerson class] isMemberOfClass:[LKPerson class]];
NSLog(@" reg1 :%hhd reg2 :%hhd reg3 :%hhd reg4 :%hhd",reg1,reg2,reg3,reg4);
BOOL reg5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
BOOL reg6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
BOOL reg7 = [(id)[LKPerson alloc] isKindOfClass:[LKPerson class]];
BOOL reg8 = [(id)[LKPerson alloc] isMemberOfClass:[LKPerson class]];
NSLog(@" reg5 :%hhd reg6 :%hhd reg7 :%hhd reg8 :%hhd",reg5,reg6,reg7,reg8);
reg1是类方法isKindOfClass,应该查找元类,很明显NSObject的元类不是NSObject,继续查找父类,NSObject的元类的父类为NSObject,返回true。
reg2是类方法isMemberOfClass,查找元类,NSObject的元类不是NSObject,返回false。
reg3查找LKPerson的元类,然后继续往上找,找到根元类,然后找到NSObject,找到nil,返回false。
reg3查找LKPerson的元类,返回false。
reg5是实例方法isKindOfClass,应该查找类,查找NSObject类比对,返回true。
reg6是实例方法isMemberOfClass,应该查找类,查找NSObject类比对,返回true。
reg7查找LKPerson类比对,返回true。
reg8查找LKPerson类比对,返回true。
查看输出
reg1 :1 reg2 :0 reg3 :0 reg4 :0
reg5 :1 reg6 :1 reg7 :1 reg8 :1