变量
成员变量
特性:
- 在@interface或@implementation里声明
- 用于类的内部,无需与外界接触,与类的生命周期一致
- 由修饰符决定子类及其他类是否可以直接访问
- 不会生成get、set方法
修饰符
- @public:在任何地方都能直接访问对象的成员变量
- @private:只能在当前类的对象方法中直接访问,如果子类要访问需要调用父类的get/set方法
- @protected:可以在当前类及其子类对象方法中直接访问(系统默认下是用它来修饰的)
- @package:在同一个包下就可以直接访问,比如说在同一个框架
注:在.h中成员变量的默认修饰符@protected. 在.m中成员变量的默认修饰符为@private.
属性
定义
提供了一个简单的方式来声明以及实现一个变量访问其方法
特性
- 以关键词@property声明,自动生成getter,setter方法(Xocde4.5以后),如没有对应的成员变量则自动生成成员变量
- 属性不是变量
- 用于与外界交互,可使用点语法访问成员变量
- @property 还可以出现在protocol 或者 category声明中
实现方式选项
- @synthesize:默认实现方式,编译器期间,让编译器自动生成getter/setter方法,声明属性=变量,意思是作用于这个变量,当没有对应成员变量时会自动创建;当有自定义的存或取方法时,会屏蔽自动生成该方法;
- @dynamic:告诉编译器,不自动生成getter/setter方法,避免编译期间产生警告;然后由自己实现存取方法或存取方法在运行时动态创建绑定:主要使用在CoreData的实现NSManagedObject子类时使用,由Core Data框架在程序运行的时动态生成子类属性
修饰符
atomic(原子性):默认属性修饰词,提供了多线程环境下对属性的安全访问和存取互斥,同一时刻,只有一个线程可以访问属性;但是读/写安全,并不是线程安全,例如对属性进行读写之外的操作;底层采用自旋锁;并发访问性能会比较低
nonatomic(非原子性):与atomic对应,一般不需要多线程支持的时候就用它,这样在并发访问的时候效率会比较高
getter=getterName:指定get方法,并需要实现这个方法 。必须返回与声明类型相同的变量,没有参数.相当于重新命名getter方法
setter=setterName:指定 set 方法,并需要实现这个方法 。带一个与声明类型相同的参数,没有返回值(返回空值)
readwirte:默认是readwrite,表示允许读/写操作
readonly:只生成getter方法,不生成setter方法,且不允许存储(KVC可修改值)
assgin:通常用于标量类型(简单变量 int , float , CGRect 等),assign不会使对象的引用计数加1,也就是说如果用assign去修饰一个对象,这个对象会立即被释放,重要的是assgin在被释放的时候是不会自动置为nil,还是保留对象的指针地址;另一种典型情况是用在对对象没有所有权的时候,通常是 delegate ,避免造成死循环(如果用 retain 的话会死循环);(MRC下是默认选项)
weak:不增加对对象的引用计数,也不持有对象,因此不能决定对象的释放。它比 assign 多了一个功能,当对象被释放自动把指针变成 nil
strong:默认选项(ARC下),表示持有该对象,并使引用计数+1
copy:复制成一个新对象,并引用计数+1;此属性只对那些实行了 NSCopying 协议的对象类型有效
深拷贝和浅拷贝
深拷贝(对象拷贝):重新申请一片内存保留这个对象,与原对象之间没有关系
浅拷贝(指针拷贝):实际上相当于引用计数+1,被拷贝的和拷贝的引用同一个对象
对象 | 修饰类型 | 结果 |
---|---|---|
immutableObject | copy | 浅拷贝拷贝 |
immutableObject | mutableCopy | 不完全深拷贝 |
mutableObject | copy | 不完全深拷贝 |
mutableObject | mutableCopy | 不完全深拷贝 |
注:集合类对象虽然新开辟了内存地址,但是存放在内存上的值(也就是数组里的元素仍然指向原数组元素值,并没有另外复制一份)
子类的重定义
你可以在子类中对一个属性进行重定义,但是你必须在子类中同样重复它的所有额外属性(除了readonly和readwrite)。对于类别或者协议中的属性也是一样的—当属性可能在类别或者协议中被重定义式,属性的所有额外属性也要被完整重复。
实例变量
定义
实例变量是数据类型为类的成员变量
私有变量
定义
OC中提供了关键字@private来声明私有变量,只允许本类访问
OC 中没有绝对的私有变量,这么说基于两点原因:
- 可修改: 通过KVC 键值编码 来修改私有成员变量的值
- 可读取 : 通过底层runtime 获取实例变量Ivar 对应私有值
全局变量
定义
在@implementation外定义或方法中的变量,在任何源文件中都可以用
修饰词
- ** static**:在Objective-C 的语法中声明后的static静态变量在其他类中是不能通过类名直接访问的,也称作私有全局变量;它只在程序开机初始化一次(并不是该类实例化后才初始化的)
- extern:声明为一个外界可见的常值变量,可在其他文件中引用
局部变量
定义
写在代码块或函数中的变量为局部变量,生命周期与函数一致,系统会自动释放
方法
类方法
也称静态方法或者工厂方法
特性
- 以加号+开头,直接可以用类名来执行的方法(类本身会在内存中占据存储空间,里面有类\对象方法列表)
- 类方法中不能访问实例变量(成员变量)
实例方法
特性
- 以减号-开头,只能让对象调用
- 对象方法能访问实例变量(成员变量)
- 类方法和对象方法可以同名
私有方法
oc中没有提供关键字来声明私有方法,可以通过catogry的匿名类Extension通过在一个只在类的.m文件中来声明一个只能被本类访问的方法。
构造方法
默认情况下,在 OC 中创建1个对象分为两部分(new):+alloc:分配内存空间;-init :初始化对象。用作初始化对象的成员变量。
自定义构造方法示例:
- (instancetype)initWithAge:(int)age andName:(NSString *)name;
// 实现自定义构造函数 在初始化的时候为属性赋值
- (instancetype)initWithAge:(int)age andName:(NSString *)name
{
if (self = [super init]) {
_age = age;
_name = name;
}
return self;
}
类别
单独提出的一个主意点:类别中的属性property
类与类别中添加的属性要区分开来,因为类别中只能添加方法,不能添加实例变量。这种情况下,是不会自动生成实例变量的,必须自己实现get/set方法。匿名类别(匿名扩展)是可以添加实例变量的,非匿名类别是不能添加实例变量的,只能添加方法,或者属性(其实也是方法)。
OC的分类允许给分类添加属性,但不会自动生成getter、setter方法,不过最好还是不要使用;
如果声明了属性,在实现文件中编译器会提示用 @dynamic 属性名字 来告诉开发者自己来写属性的setter方法和getter方法,而这里实现setter和getter需要用到声关联对象(存取方法在运行时动态创建绑定)。
锁
信号量、NSLock和synchronized
面试问题
- OC语言的动态性怎么解释
答:他的对象类型和真正要调用的方法是在运行时才确定的,所以这就决定了在oc中没有绝对的私有变量和私有方法的,通过运行时机制runtime我们可以动态的去对类中所有的变量和方法动手脚
引用:
iOS成员变量和属性的区别iOS 成员变量 实例变量 属性变量IOS 成员变量,全局变量,局部变量定义,static与extern的区别iOS 修饰词 详解[爆栈热门 iOS 问题] atomic 和 nonatomic 有什么区别?