//属性的属性
属性定义在一个 .h文件里,在这个.h文件里可以定义实例变量(就是这个类的特征),也可以通过 @protery(属性约束关键字) 属性名字类型 属性名 来定义一些属性,在property里面重置setter或者getter的方法名(例如:@property(readwrite,setter=haha:,getter=dedaomingnzi) NSString *name;)属性的约束有:读写约束(readonly、readwrite)原子约束(atomic)非原子约束
也可以在.m文件里定义当前类的私有的实例变量和私有方法(私有方法在声明的时候也在.m文件里声明,如果在.h文件里声明,那就是能够提供给外部接口的方法了)这就是一个类的延展(Extension);如果一个我们看不到源代码的类,我们需要他的一些方法的实现,但是该类没有实现,那就建立一个分类 ,注意分类只能仅仅是添加类的方法,category;
/*
1.读写特性(写在 property 关键字后面的 括号内 如果不设置的话,那就是默认的readwrite)
readonly(只能去读(获取值)不能写,只有getter方法,只能获取值,不能写)
readwrite(默认的特性 既可以读又可以写,相当于他有getter和setter方法,可以访问( 值)也可以赋值)
setter= 的用法:他是设置 setter 方法的名字 例如:@property(readwrite,setter = haha:) NSString *name;我们在使用的时候,直接 [对象 haha:消息];
getter= 设置getter的方法名字,也就是修改 getter 方法的名字
2.原子特性
atomic 原子特性
nonatomic 非原子特性
原子特性 与 非原子特性 的区别:在我们用setter getter 方法的时候,系统默认的是原子特性,原子特性是保护我们的线程安全(多加了个上锁 开锁的过程)好处:保护属性的安全 坏处:占用系统资源
非原子特性:没有做线程处理,(只是简单的生成setter 和 getter 方法)(苹果推荐使用的特性)
线程:就是同时的做多件事
3.语义特性
assign (系统默认的特性)通常使用于基本类型 NSInterger,CGFloat,在取值与值的时候,只是简单的取值与赋值操作(就是里面自己写了 _name = name 的方法)
retain 通常使用于 所有的对象类型 setter getter 方法就会自动生成内存优化的的代码
copy 通常适用于对象类型,服从NSCoping 协议的对象类型才会使用 例如 NSString
**/
什么是KVC
//KVC 就是三个单词的简写 (key-value-coding)键值编码
//为实例变量赋值的另一种机制,是一种间接访问对象的实例变量的机制
Person * per = [[Person alloc]init];
//在外部无法访问受保护的实例变量,也没用定义setter getter 这时候可以通过KVC
//setValue:forKey:间接的给实例变量赋值 取值就是[对象 valueForKey:@“key”];
//赋值过程
//1.系统先检查有没有name这个实例变量
//2.如果没有,检查有没有同名的带有下滑线的实例变量,_name.如果找到的话,就为他赋值
//3.如果还没有的话就准备crash,他就会自动的调用一个方法,setValue:forUndefinedKey:这个方法
[per setValue:@"Niujianwei" forKey:@"na"];
[per setValue:@"男" forKey:@"gender"];
[per setValue:@"Niuni" forKey:@"id"];
[per setValue:@"sd" forKey:@"name1"];
NSLog(@"%@",[per valueForKey:@"na"]);
//一般通过KVC方法我们一般都要重写 setValue:forUndefinedKey 和 valueForUndefinedKey 两个方法
NSLog(@"%@",per);
//有时候我们为了避免出错 吧 id 改为 ID 因为 id 可能代表所有类型
// NSString * ID
//有时候通过间接的找不到id 就找 _id 再找不到 就走报错的处理路线(注意报错的路线也可以给某个变量赋值)
//对应的取值过程
//1.先检查有没有 name 这个实例变量
//2.如果没有,检查有没有和他同名的带有下划线的实例变量 _name ,有的话就直接取值
//3.如果没有的话,直接走我们的自动调用valueForUndefinedKey:方法
//下面方法也是给实例变量赋值
// per setValue:<#(id)#> forKeyPath:<#(NSString *)#>
Phone * phone = [[Phone alloc]init];
[phone setValue:@"iphone" forKey:@"brand"];//间接为手机赋值
[per setValue:phone forKeyPath:@"phone"];
NSLog(@"%@",[per valueForKey:@"phone"]);
NSLog(@"%@",[per valueForKeyPath:@"phone.brand"]);//通过路径
[per setValue:@"小米手机" forKeyPath:@"phone.brand"];
NSLog(@"%@",[per valueForKeyPath:@"phone.brand"]);
setValue: forKey setValue: forKeyPath:
这段代码有什么问题吗:
@implementation Person
- (void)setAge:(int)newAge {
self.age = newAge;//点语法用在”=“的左边,就是setter 方法,self是调用当前setter 方法的对象,这样就导致了死循环,所以不能这样使用哦
}
@end
什么是Protocol?什么是代理?写一个委托的interface?委托的property声明用什么属性?为什么?
协议提供了一组方法,但是并不负责实现,如果一个类遵循了某个协议,并且实现了协议里面的方法,那么我们称这个类就是遵循了某个协议的代理。属性的声明使用assign,防止出现循环引用的问题。
分别描述类别(categories)和延展(extensions)是什么?以及两者的区别?继承和类别在实现中有何区别?为什么Category只能为对象添加方法,却不能添加成员变量?
category类目:在不知道源码的情况下为一个类扩展方法,extension:为一个类声明私有方法和变量。
继承是创建了一个新的类,而类别只是对类的一个扩展,还是之前的类。
类目的作用就是为已知的类添加方法。
KVC键值编码,可以直接通过字符串的名字(key)来间接访问属性的机制,而不是通过调用getter和setter方法访问。
对应代码:
// // main.m #import <Foundation/Foundation.h> #import "Person.h" #import "Phone.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!"); //KVC 就是三个单词的简写 (key-value-coding)键值编码 //为实例变量赋值的另一种机制,是一种间接访问对象的实例变量的机制 Person * per = [[Person alloc]init]; //在外部无法访问受保护的实例变量,也没用定义setter getter 这时候可以通过KVC //setValue:forKey:间接的给实例变量赋值 //赋值过程 //1.系统先检查有没有name这个实例变量 //2.如果没有,检查有没有同名的带有下滑线的实例变量,_name.如果找到的话,就为他赋值 //3.如果还没有的话就准备crash,他就会自动的调用一个方法,setValue:forUndefinedKey:这个方法 [per setValue:@"Niujianwei" forKey:@"na"]; [per setValue:@"男" forKey:@"gender"]; [per setValue:@"Niuni" forKey:@"id"]; [per setValue:@"sd" forKey:@"name1"]; NSLog(@"%@",[per valueForKey:@"na"]); //一般通过KVC方法我们一般都要重写 setValue:forUndefinedKey 和 valueForUndefinedKey 两个方法 NSLog(@"%@",per); //有时候我们为了避免出错 吧 id 改为 ID 因为 id 可能代表所有类型 // NSString * ID //有时候通过间接的找不到id 就找 _id 再找不到 就走报错的处理路线(注意报错的路线也可以给某个变量赋值) //对应的取值过程 //1.先检查有没有 name 这个实例变量 //2.如果没有,检查有没有和他同名的带有下划线的实例变量 _name ,有的话就直接取值 //3.如果没有的话,直接走我们的自动调用valueForUndefinedKey:方法 //下面方法也是给实例变量赋值 // per setValue:<#(id)#> forKeyPath:(NSString *) Phone * phone = [[Phone alloc]init]; //为phone的实例变量brand赋值 [phone setValue:@"iphone" forKey:@"brand"]; //通过路径:间接为手机赋值 [per setValue:phone forKeyPath:@"phone"]; NSLog(@"%@",[per valueForKey:@"phone"]); NSLog(@"%@",[per valueForKeyPath:@"phone.brand"]);//通过路径 //通过路径:为per的实例变量phone的实例变量brand赋值 [per setValue:@"小米手机" forKeyPath:@"phone.brand"]; NSLog(@"%@",[per valueForKeyPath:@"phone.brand"]); // per setValuesForKeysWithDictionary:<#(NSDictionary *)#> } return 0; }