iOS-8.成员变量、实例变量、属性

743 阅读3分钟

ios底层文章汇总

1. 类的定义和实现LGPerson

image.png

  • 成员变量:类的定义或者类的实现中,在{ }中所声明的变量都为成员变量。成员变量用于类内部(不会生成setter、getter方法),不需与外界接触的变量。

  • 实例变量:是一种特殊的成员变量,实例变量本质上就是成员变量,只是实例是针对类而言,实例是指类的声明,如果成员变量的类型是类类型,那么这样的成员变量就是实例变量

  • 属性:为方便类对象通过点语法访问了属性,编译后会生成带下划线的成员变量, 属性创建过程中自动产生了setter 和getter方法和带下划线的成员变量。可以设置只读或者可写等,设置方法也可自定义。属性是用于提供外部访问的变量。

2. clang 编译查看.cpp文件

clang编译命令

clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.2.sdk  main.m

image.png

详见:ios - 函数签名和Type Encodings

3. strong & copy & weak 底层分析

  • 用copy和strong修饰的属性,clang编译成.cpp后setter方法不同

image.png

copy修饰的属性使用了objc_setProperty,而strong修饰的没有?

  • 在LLVM源码中搜索”objc_setProperty,找到getOptimizedSetPropertyFn方法

image.png

针对不同的修饰符,返回的name是不同的:

  • 如果是atomic & copy修饰,name为objc_setProperty_atomic_copy

  • 如果是atomic 且没有copy修饰,name为 objc_setProperty_atomic

  • 如果是nonatomic & copy 修饰,name为 objc_setProperty_nonatomic_copy

  • 其他剩余的组合,即nonatomic、nonatomic & strong、nonatomic & weak等,name为objc_setProperty_nonatomic

llvm编译属性流程: 属性的setter方法setPropety进入llvm后,llvm遍历ivar进行优化处理,对修饰符判断返回一个sel绑定一个value

上述的几个name分别对应objc-781源码中的如下方法

image.png

然后通过汇编调试发现,最终copy和strong修饰的属性都会走到objc_storeStrong

  • copy修饰的属性汇编调试结果

image.png

  • strong修饰的属性汇编调试结果

image.png

  • 源码中搜索objc_storeStrong,有如下源码,主要也是retain新值,release旧值
void
objc_storeStrong(id *location, id obj)
{
    id prev = *location;
    if (obj == prev) {
        return;
    }
    objc_retain(obj);//retain新值
    *location = obj;
    objc_release(prev);//release旧值
}

结论

  • copystrong修饰的属性在底层编译的不一致,主要还是llvm中对其进行了不同的处理的结果。copy的赋值是通过objc_setProperty,而strong的赋值时通过self + 内存平移(即将指针通过平移移至name所在的位置,然后赋值),然后还原成 strong类型
  • strong & copy 在底层调用objc_storeStrong,本质是新值retain,旧值release
  • weak 在底层调用objc_initWeak

4. imp & SEL

SEL:方法编号,相当于书本目录的名称

IMP:函数指针地址,相当于书本目录的页码

1:首先需要找到书本的什么内容 (sel 目录里面的名称)

2:通过名称找到对应的本⻚码 (imp)

3:通过⻚码去定位具体的内容

5. 成员变量、实例变量、属性区分

    1. 定义在{}号中的除去基本数据类型int float ....等,其他类型的变量都叫做实例变量

    实例变量+基本数据类型变量=成员变量

    1. 成员变量不能外部访问,如需访问可以自定义setter getter方法或者将变量定义为属性
@interface ViewController : UIViewController
@property (nonatomic, copy) NSString *string;
@end
  • 如果  { NSString *string; } 并且 @synthesize string; 则不会自动生成_string实例变量,通过string和self.string获取变量;

  • 如果{ NSString *_string; } 并且 @synthesize string; 则_string与self.string不是同一个变量,string与self.string同一个变量;

  • 如果  @synthesize string; 则不会自动生成_string实例变量,通过string和self.string获取变量;