内容字号:默认大号超大号

段落设置:段首缩进取消段首缩进

字体设置:切换到微软雅黑切换到宋体

iOS基础系列:属性及成员变量详解

2018-07-10 18:04 出处:清屏网 人气: 评论(0

首先创建个类,然后声明属性及成员变量

TestObj() {
    NSString *_str11;
    NSString *_str12;

    int _f1;
    int _f2;
}
 (nonatomic, nonnull, copy) NSString *str21; (nonatomic, nonnull, copy) NSString *str22; (nonatomic, assign) int f21;

通过clang -rewrite-objc TestObj.m 生成TestObj.cpp

  1. 从这里面的 我们可以看到, 我们可以使用 -> 获取属性或者成员变量
  2. 并且如果属性和成员变量同为str11属性生成的成员变量会覆盖本身定义的_str11成员变量
struct TestObj_IMPL {
    struct NSObject_IMPL NSObject_IVARS; // 指向类的指针
    NSString *_str11;
    NSString *_str12;
    int _f1;
    int _f2;
    int _f21;
    NSString * _Nonnull _str22;
};
  • 1. nonnull、nullable、null_resettable、null_unspecified这几个是直接在前面加的关键字,直接由编译器识别并优化以更好的与swift对接。
  • 2. 使用copy和不使用copy的set方法不一样(下列例子不够清晰,可以自行增加属性测试,或者看后续文章)。
static NSString * _Nonnull _I_TestObj_str11(TestObj * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_TestObj$_str11)); }
// 这里引入objc_setProperty函数
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);

static void _I_TestObj_setStr11_(TestObj * self, SEL _cmd, NSString * _Nonnull str11) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct TestObj, _str11), (id)str11, 0, 1); }

static NSString * _Nonnull _I_TestObj_str22(TestObj * self, SEL _cmd) { return (*(NSString * _Nonnull *)((char *)self + OBJC_IVAR_$_TestObj$_str22)); }
static void _I_TestObj_setStr22_(TestObj * self, SEL _cmd, NSString * _Nonnull str22) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct TestObj, _str22), (id)str22, 0, 1); }

static int _I_TestObj_f21(TestObj * self, SEL _cmd) { return (*(int *)((char *)self + OBJC_IVAR_$_TestObj$_f21)); }
static void _I_TestObj_setF21_(TestObj * self, SEL _cmd, int f21) { (*(int *)((char *)self + OBJC_IVAR_$_TestObj$_f21)) = f21; }

我们再来看看setter函数的 objc_setProperty函数

  • 1. id self, SEL _cmd是函数默认的2个函数。
  • 2. ptrdiff_t offset指针偏移地址
  • 3. id newValue新的值
  • 4. BOOL atomic是否是原子操作
  • 5. signed char shouldCopy 是否为copy
  • 6. 注意点:NSMutableArry使用copy修饰最终会进入reallySetProperty,并调用copyWithZone方法,至于会出现什么后果,我们后面再讲。
void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy) 
{
// 注意这里 0为nocopy 1为copy 2为MUTABLE_COPY 
// shouldCopy != MUTABLE_COPY 优先运算
    bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
    bool mutableCopy = (shouldCopy == MUTABLE_COPY);
    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);

    if (copy) {
        newValue = [newValue copyWithZone:nil];
    } else if (mutableCopy) {
        newValue = [newValue mutableCopyWithZone:nil];
    } else {
        if (*slot == newValue) return;
        newValue = objc_retain(newValue);
    }

    if (!atomic) {
        oldValue = *slot;
        *slot = newValue;
    } else {
        spinlock_t& slotlock = PropertyLocks[slot];
        slotlock.lock();
        oldValue = *slot;
        *slot = newValue;        
        slotlock.unlock();
    }

    objc_release(oldValue);
}
分享给小伙伴们:
本文标签: iOS

相关文章

发表评论愿您的每句评论,都能给大家的生活添色彩,带来共鸣,带来思索,带来快乐。

CopyRight © 2015-2016 QingPingShan.com , All Rights Reserved.

清屏网 版权所有 豫ICP备15026204号