美文网首页
OC对象的本质

OC对象的本质

作者: 苏苏慢跑 | 来源:发表于2021-03-25 13:53 被阅读0次

    在main文件里,是这样实现的

    #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

    就看到产生了main.cpp文件,打开看下里面的代码,在里面找到Person的结构体如下

    截屏2021-03-25 下午1.19.07.png

    可以看到Person类在cpp文件里是一个struct,也就是结构体

    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方法调用的是objc_setProperty,它是所有属性set方法的封装函数
    static void _I_Person_setName_(Person * self, SEL _cmd, NSString *name) {
     objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct Person, _name), (id)name, 0, 1); }
    
    

    我在源码里找到了这个方法的实现,实现的本质其实就是给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); //实现函数
    }
    
    
    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了一次,对应上面的retain
    }
    
    • 总结:对象的本质是结构体

    再看main.cpp文件下方,有很多熟悉的结构体可以做很多研究,先写到这里。

    附上关于clang遇到的问题,以及解决方案

    clang -rewrite-objc main.m -o main.cpp 把⽬标⽂件编译成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,根据自己机器的环境做调整

    xcode安装的时候顺带安装了xcrun命令,xcrun命令在clang的基础上进⾏了
    ⼀些封装,要更好⽤⼀些
    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 (⼿机)

    相关文章

      网友评论

          本文标题:OC对象的本质

          本文链接:https://www.haomeiwen.com/subject/xkwlhltx.html