【Objective-C 篇】 ☞ 2. 属性、方法
1. 属性(Property)和实例变量(instance variable)
1.1 当定义一个属性时,本质上是在干什么(编译器在帮我们干什么):
1) 生成实例变量用来保存属性的值
2) 生成访问器(setter和getter方法)用于修改和访问属性的值
1.2 实际开发中知道的事:
1) 只读属性:只能读取值,不能修改值。这种属性只生成getter方法,不生成setter方法。
2) 计算属性:没有对应的实例变量,属性的值经常是通过计算得到的。在swift中,这种属性叫计算属性。
3) 自定义setter/getter:一个属性的getter方法和setter方法都可以由程序员自定义。当程序员不满意编译器生成的访问方法(setter/getter)时,可以自定义。
a.如果只自定义了setter方法,编译器补上getter方法和实例变量
b.如果只自定义了getter方法,编译器补上setter方法和实例变量
c.如果自定义了getter和setter,编译器就会认为你不需要实例变量,不会补上实例变量
1.3 属性的其他细节
1) 如果getter和setter都自定义了,实例变量就不会自动生成,但如果需要实例变量,可以使用属性合成器synthesize指定实例变量:
在implementation中,加一句: @synthesize 属性名 = 实例变量名;
//使用属性合成器指定属性所对应的实例变量 @synthesize age = _age;//此时编译器会生成_age这个实例变量 |
2) 如果getter方法和setter方法不需要编译器生成,可以在.m文件中使用 @dynamic 来要求编译器不要生成访问方法。
应用场景:一般会在CoreData的代码使用这种方式。
@dynamic 属性名; //不要生成此属性的setter和getter
特殊属性,编译器不生成setter和getter,程序在运行时才通过特殊手段获得setter和getter方法。
经常会在CoreData的代码中看到这种情况。(如:属性的值需要获取后台数据库读到)
3) 实例变量的访问范围
- 在接口部分(.h文件中)定义的实例变量默认(@protect)可以在本类的内部,及子类的内部访问。
- 在.m文件中定义的实例变量,只能在本类的内部访问。其实地方都访问不了。都是私有的。
- 在接口部分(.h文件中)定义的实例变量如果真希望别人也访问,可以用@public将其公开。我们不建议这么做。
//实例变量的访问修饰符 { @protected //默认是保护,可省略不写 int protectedVar;//默认是保护的,只能在本类内部及子类内部访问 @public int publicVar;//公开的实例变量,一般不这样做 @private int privateVar;//私有的实例变量,只能在本类的的内部访问 } |
2. 初始化方法(构造方法)
2.1 概念
一种特殊的方法,专门用于初始化对象。
在OC中init开头的方法,我们称之为初始化方法(构造方法)。
构造方法的用途:用于初始化一个对象,让某个对象一创建出来就拥有某些属性和值
[[类型 alloc]init]; //init就是初始化方法
2.2 怎么写
任何一个对象,都默认有一个初始化方法:init,是从NSObject类中继承来的。
如果程序员不满意继承来的init方法,可以自己重写。
怎么写?固定写法:
1) 必须先调用父类的初始化方法,并将返回值赋值给self(self是指向当前对象的引用)
2) 如果父类初始方法调用成功,此时给对象中的属性赋初始值。初始化对象的主要目的就是给属性赋值。
3) 方法结束时,必须返回当前对象(self).
注意: 初始化方法返回空代表初始化失败
2.3 初始化方法的注意事项
1) 初始化方法可以有多个,初始化对象时可以选择的调用。
2) 当一个类没有提供任何初始化方法时,也有init方法。从父类继承来的init方法会将所有的属性初始化为0.
3) 关于空(nil),在OC中表示空指针的字面值是nil,相当于C语言中的NULL
4) 返回值类型instancetype(instancetype会自动把返回值类型变成具体的类型)
- 从iOS7 SDK开始, 初始化方法,以及创建对象的工厂方法,其返回值全部使用instancetype类型。
- instancetype会自动根据方法的返回对象识别返回类型(返回什么类型的对象instancetype就变成什么类型,instancetype会自动知道返回值的类型),instancetype只能出现在返回值类型上。
2.4 id类型
id类型是动态类型,当程序运行到这句话时,才知道这句话某一个变量是什么类型。
id类型定义的变量,它里面存的这个值的类型不确定。运行时才确定,编译时也不确定。也叫万能指针。
- id类型是万能类型,有风险;id类型只针对对象类型,不针对基本类型;id类型只能指向对象。是一种通用对象类型!
- id类型的变量其实是一个可以指向任何类型对象的引用(指针),类似于C语言中的void*(万能指针)
如:id r = [[TRPerson alloc]init];
id类型被定义为指向NSObject子类的实例对象的指针
double d = 10.5;
id a = &d;//ERROR
id是一个指针,但在使用时无需加*
id stu = nil;
id类型的变量可以出现在变量能出现的任何地方,比如方法的参数上,返回值类型上,或直接定义局部变量等。
使用id类型的好处:可以指向任何对象; 坏处:编译器失去了对类型的检查。
总结:id和instancetype的区别
- id可以做方法的返回值类型,方法的参数类型,还可以直接声明变量,或定义成属性
- instancetype只能做初始化方法和工厂方法的返回值类型,不能在方法的参数等地方使用instancetype
instancetype类型比id类型好一点:因为instancetype会自动把它的返回值类型转换成它具体的类型。而id类型则是万能类型,带有一定的风险(还要做一些类型转换,多了一些步骤,性能和效率会低一点)。
3. 类方法(class method)
3.1 概念
1) 实例方法(instance method):
以"-"号开头的方法叫实例方法
必须通过实例(对象)去调用,向对象发消息会调用实例方法
2) 类方法
以"+"号开头的方法叫类方法
必须通过类去调用,向类发消息就会调用类方法
如果一个方法的具体实现与对象无关(即不会使用对象的属性或实例变量),就可以考虑写成类方法!!!
注意:
类方法中不能使用类的成员变量!(即在类方法中不能直接访问对象的东西)
在实例方法中可以使用类的成员变量!
3.2 为什么使用类方法
1) 类方法的调用比较方便,不用创建对象就可以
2) 如果有一个方法,不需要使用某个对象属性,那么可以考虑写成类方法,为了方便调用。
3) 经常使用类方法来创建对象,这种类方法被称为简单工厂方法,或直接叫工厂方法
在类方法中,不能直接访问属性和实例变量,也不能直接调用实例方法。(与对象有关的操作在类方法中都不能用!)
类方法属于整个类,和具体的对象无关,所以对象的属性和实例变量不能在类方法中访问。
4. 工厂方法(Factory Method)
一个类为了方便创建对象,提供一个类方法返回一个新对象,这个类方法就叫工厂方法。是简单工厂模式的具体体现。
工厂方法就是把alloc方法和init…方法合并写成一个方法。
工厂方法的方法名格式:类名WithXXX…开头(类名首字母小写)
TRPoint *p1 = [[TRPoint alloc]initWithX:1 andY:2];//一般创建对象
TRPoint *p2 = [TRPoint pointWithX:2 andY:4];//用工厂方法创建对象
5. 单例模式(Singleton):就是单个实例的意思。是一种特殊的工厂方法。一个类只允许创建一个对象。
什么是单例模式:
1)主要用于做应用程序的资源共享控制
2)只能生成唯一的对象
3)利用类方法来创建和访问对象
单例模式的原理:
1)类中定义一个实例(static全局变量)
2)类中定义一个类方法作为单例方法
3)在单例方法中如果类中定义的实例为空,则创建该类的实例;否则返回此实例。
单例模式的好处:节约资源、提高效率、统一管理。
NSNotificationCenter 通知中心 也是一个单例类
UIApplication(代表一个应用程序,App是唯一的) 就是一个单例类
设计模式:(经典23种设计模式)
解决一个典型问题的最佳方案。
工厂模式: 简单工厂模式(工厂方法) 工厂模式 抽象工厂
简写方式:[TRPoint new];相当于写[[TRPoint alloc]init]; (一个意思的不同写法)
[[TRPoint alloc]init]这种写法方便重写初始化方法(init..),[TRPoint new]这种写法不能。