在main文件里,是這樣實現(xiàn)的
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation Person
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
}
return 0;
}
把main.m文件編譯為cpp文件,命令為:
clang -rewrite-objc main.m -o main.cpp
就看到產(chǎn)生了main.cpp文件,打開看下里面的代碼,在里面找到Person的結(jié)構(gòu)體如下

截屏2021-03-25 下午1.19.07.png
可以看到Person類在cpp文件里是一個struct,也就是結(jié)構(gòu)體
struct Person_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_name;
};
- struct NSObject_IMPL NSObject_IVARS; 是isa指針,下方_I_Person_name是get方法,I_Person_setName 是set方法,而set方法調(diào)用的是objc_setProperty,它是所有屬性set方法的封裝函數(shù)
static void _I_Person_setName_(Person * self, SEL _cmd, NSString *name) {
objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct Person, _name), (id)name, 0, 1); }
我在源碼里找到了這個方法的實現(xiàn),實現(xiàn)的本質(zhì)其實就是給set新值并且釋放舊值
void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy)
{
bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);//判斷屬性copy
bool mutableCopy = (shouldCopy == MUTABLE_COPY);//判斷屬性mutableCopy
reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy); //實現(xiàn)函數(shù)
}
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
if (offset == 0) {
object_setClass(self, newValue);
return;
}
id oldValue;
id *slot = (id*) ((char*)self + offset);
//得到新值newValue
if (copy) {
newValue = [newValue copyWithZone:nil];
} else if (mutableCopy) {
newValue = [newValue mutableCopyWithZone:nil];
} else {
if (*slot == newValue) return;
newValue = objc_retain(newValue); //retain新值newValue
}
if (!atomic) {//非原子型屬性修飾, oldValue存放舊值,*slot存放新值
oldValue = *slot;
*slot = newValue;
} else {//原子型操作,使用自旋鎖保證set方式的安全,并oldValue存放舊值,*slot存放新值
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
objc_release(oldValue);//釋放舊值
}
在這里忽然想起被問過這樣一個問題,atomic修飾的屬性,是在set時用了自旋鎖還是set/get都用了。首先上面代碼set肯定是用了。這里一眼看到了源碼,貼出來。所以atomic修飾的屬性在set/get時都用到了自旋鎖
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
if (offset == 0) {
return object_getClass(self);
}
// Retain release world
id *slot = (id*) ((char*)self + offset); //獲取屬性的值
if (!atomic) return *slot; //非原子型就直接反回了
// Atomic retain release world 下面都是原子型的get
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);//獲取屬性值,并retain了一次
slotlock.unlock();
// for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
return objc_autoreleaseReturnValue(value);//屬性autorelease了一次,對應(yīng)上面的retain
}
- 總結(jié):對象的本質(zhì)是結(jié)構(gòu)體
再看main.cpp文件下方,有很多熟悉的結(jié)構(gòu)體可以做很多研究,先寫到這里。
附上關(guān)于clang遇到的問題,以及解決方案
clang -rewrite-objc main.m -o main.cpp 把?標(biāo)?件編譯成c++?件
UIKit報錯問題
clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot /
Applications/Xcode.app/Contents/Developer/Platforms/
iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk main.m
這里可能不是iPhoneSimulator13.0.sdk,根據(jù)自己機器的環(huán)境做調(diào)整
xcode安裝的時候順帶安裝了xcrun命令,xcrun命令在clang的基礎(chǔ)上進?了
?些封裝,要更好??些
xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o
main-arm64.cpp (模擬器)
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main?arm64.cpp (?機)