------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
1.点语法的介绍
1、使用“点语法”
Student*stu = [[Studentalloc] init];
// 设置age的值
stu.age= 10; // 等价于[stu setAge:10];
// 取出age的值
int age = stu.age; // 等价于int age = [stu age];
NSLog(@"age is %i", age);
这里的stu.age并不是代表直接访问stu对象的成员变量age,而是编译器遇到stu.age = 10的时候会自动将代码展开成[stu setAge:10]
把原来的int age = [stu age]替换成了int age = stu.age。这两种写法又是完全等价的,
stu.age并不是直接访问stu对象的成员变量age,而是编译器遇到int age = stu.age的时候会自动将代码展开成int age = [stu age]
OC点语法的本质是方法调用,不是直接访问成员变量。至于这个点语法代表的是get方法还是set方法,
那就取决于你是取值还是设值(也可以理解为点语法是在“=”的左侧还是右侧,左侧:如 stu.age=…. 这就是调用set方法,右侧 … = stu.age 这就是调用get方法),
取值就是get方法,设值就是set方法
点语法的本质是方法的调用,而不是访问成员变量,当使用点语法时,编译器会自动展开成相应的方法。
切记点语法的本质是转换成相应的set和get方法,如果没有set和get方法,则不能使用点语法。
2.@property和 @synthesize
@property是编译器的指令
什么是编译器的指令,编译器指令就是用来告诉编译器要做什么
@property 告诉编译器声明属性的访问器(getter/setter)方法
@property 类型 方法名
在老式的代码中:
@property只能写在@interface @end中
@property 用来自动生成成员变量的get/set方法声明(xcode4.4以前)
告诉property要生成的get/set方法声明的成员变量类型是什么
告诉property要生成的get/set方法是哪个属性的,属性名称去掉下划线
@synthesize是在m文件中定义set和get方法的实现。和@property配合使用..........但是,现在时代不同啦
@property的增强使用:
只使用@property 进行声明,类自动帮你实现。
xcode4.4以后property做了增强
帮助我们自动生成get/set方法的声明
帮助我们自动生成get/set方法的实现
如果没有手动声明成员变量,perperty会在.m文件中自动帮我们生成一个_开头的成员变量。但是如果想让子类继承父类的成员变量,还是必须在.h中手动写成员变量。
1)如果手动实现了set方法,那么编译器就只生成get方法和成员变量;
2)如果手动实现了get方法,那么编译器就只生成set方法和成员变量;
3)如果set和get方法都是手动实现的,那么编译器将不会生成成员变量,并且报错。因为编译器觉得你在玩弄它,呵呵。
3.动态类型和静态类型
多态:允许不同的类定义相同的方法。
动态类型:程序直到执行时才能确定所属的类。 Animal *ani = [Dog new];
静态类型:将一个变量定义为特定类的对象时,使用的是静态形态。Animal *ani = [Animal new];
4.id类型以及应用
id类型是一种通用的对象类型,它可以用来存储属于任何类的对象。也可以理解为万能指针。
在id的定义中,已经包好了*号。id指针只能指向oc的对象。
id类型的定义
Classisa;
Typedefstructobjcobject{
}*id;
局限性:调用一个不存在的方法,编译器会马上报错。
iOS5之后推出了instancetype类型
相同点
1)instancetype和id的异同
不同点
2)都可以作为方法的返回类型
①instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象;
②instancetype只能作为返回值,不能像id那样作为参数。
5.动态类型检测方法
1)在objective-c中,一个对象是否调用指定的方法不是由编译器决定而是由运行时决定,这被称作是方法的动态绑定。
2)在objective-c里,对象不调用方法,而是接收消息,消息表达式为: [reciver message];运行时系统首先确定接收者的类型(动态类型识别),
然后根据消息名在类的方法列表里选择相依的方法执行,所以在源代码里消息也称为选择器(selector)。
3)消息函数的作用:
首先通过第一个参数的receiver,找到它的isa 指针,然后在isa 指向的Class 对象中使用第二个参数selector 查找方法。
如果没有找到,就使用当前Class 对象中的新的isa 指针到上一级的父类的Class 对象中查找;
当找到方法后,再依据receiver 的中的self 指针找到当前的对象,调用当前对象的具体实现的方法(IMP),然后传递参数,调用实现方法。
假如一直找到NSObject 的Class 对象,也没有找到你调用的方法,就会报告不能识别发送消息的错误。
对象在运行时获取其类型的能力称为内省。内省可以有多种方法实现。
1)判断类型
-(BOOL) isKindOfClass: classObj 判断实例对象是否是这个类或者这个类的子类的实例。
判断实例对象是否是另一个类类型
-(BOOL) isMemberOfClass: classObj判断是否是这个类的实例,不管是否是这个类的子类的实例。
+(BOOL)isSubclassOfClass:classObj 判断类是否是指定类的子类
判断对象能否相应指定的方法:
-(BOOL) respondsToSelector: selector 判读实例是否有这样方法能响应selector方法
+(BOOL) instancesRespondToSelector: 判断类是否有这个方法。此方法是类方法,不能用在类的对象
响应方法
-(id)performSelector:selector 应用selector指定的方法
-(id)performSelector:selectorwithObject:object(应用selector指定的方法,传递参数object)
-(id)performSelector:selectorwithObject:object1withObject:object2(应用selector指定的方法,传递参数object1和object2)
6.构造方法
构造方法:用来初始化对象实例变量值的方法,是个对象方法,-开头
重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值
Person *p = [Person new];
new方法的内部会分别调用两个方法来完成3件事情
(1)使用alloc方法来分配存储空间(返回分配的对象)
(2)使用init方法来对对象进行初始化
(3)返回对象的首地址
Person *p = [[Person alloc] init];
(1)init方法就是构造方法,是用来初始化对象的方法,注意这是一个对象方法,以减号开头。
默认初始化完毕后,所有成员变量的值都为0。
(2)alloc向某个类发送alloc消息的结果,为该类分配内存,以存放该类的全部实例变量,还将这块内存区域全部初始化为0
一个刚刚分配的对象并不能立即使用,需要先初始化该对象,然后才能使用它,但由于未进行初始化,随后可能出现一些不可预测的行为
重写构造方法:
-(id/instancetype)init{
if(self = [super init]){
//为子类增加属性进行初始化
}
return self;
}
1. [super init]的作用:
面向对象的体现,先利用父类的init方法为子类实例的父类部分属性初始化。
2. self 为什么要赋值为[super init]:
简单来说是为了防止父类的初始化方法release掉了self指向的空间并重新alloc了一块空间(可能性很小)。
这时的话,[super init]可能alloc失败,这时就不再执行if中的语句。
3. super作为消息接受者的实质:
super并不是真正的指针,[super message]的实质是由self来接受父类的message。
需要注意的是,[super message]中,message方法出现的self为[super message]语境中的self,即子类实例。
创建一个人的类,默认年龄是10岁
@interface Person : NSObject
@property int age;
@end
@implementation Person
-(id) init{
if( self = [super init]){
_age =10;
}
return self;
}
@end
调用:
Person *p = [[Person alloc] init];
NSLog(@"%d" , p.age);
构造方法使用注意
(1)子类拥有的成员变量包括自己的成员变量以及从父类继承而来的成员变量,
在重写构造方法的时候应该首先对从父类继承而来的成员变量先进行初始化。
(2)原则:先初始化父类的,再初始化子类的。
(3)重写构造方法的目的:为了让对象方法一创建出来,成员变量就会有一些固定的值。
(4)注意点:
先调用父类的构造方法[super init];
再进行子类内部成员变量的初始化。
自定义的构造方法:
自定义构造方法的规范
(1)一定是对象方法,以减号开头
(2)返回值一般是id(instancetype)类型
(3)方法名一定以initWith开头
@interface Person : NSObject
@property int age;
@property NSString * name;
-(id) initWithName: (NSString *)name;
-(id)initWithName:(NSString *)name andAge:(int )age;
@end
@implementation Person
-(id) initWithName: (NSString *)name{
if(self = [super init]){
_name = name;
}
return self;
}
-(id)initWithName:(NSString *)name andAge:(int )age{
if(self = [super init ]){
_name = name;
_age = age;
}
return self;
}
@end
然后定义一个学生类,继承自Person类,并且自定义构造方法接收三个参数
@interface Student : Person
@property int no;
-(id)initWithName: (NSString * )name andAge:(int)age andNo:(int)no;
@end
@implementation Student
-(id)initWithName: (NSString * )name andAge:(int)age andNo:(int)no{
if(self = [super init ] ) {
_name = name;
_age = age;
_no = no;
}
return self;
}
@end
主程序测试:
Person *p = [[Person alloc] initWithName:@"dashi"];
NSLog(@"%@",p.name);
Person *p1 = [[Person alloc] initWithName:@"dashixiong" andAge:18];
NSLog(@"%@,%d",p1.name,p1.age);
Student *p2 = [[Student alloc] initWithName:@"dashidi" andAge:10 andNo: 12];
NSLog(@"%@,%d,%d",p2.name,p2.age,p2.no);
自定义构造方法的使用注意
(1)自己做自己的事情
(2)父类的方法交给父类的方法来处理,子类的方法处理子类自己独有的属性