标签:
KVC(Key-Value Coding)键值编码
KVO(Key-Value Observing)键值观察
这两个方法都是runtime方法 运行时方法
KVC:
KVCClass *kvc = [KVCClass new];
//通过setValue: forKey:来动态设置属性的值
[kvc setValue:@"我是同过setValue方法设置的值" forKey:@"name"];
//通过valueForkey来获取值
NSLog(@"name = %@", [kvc valueForKey:@"name"]);
我们可以通过键路径给实例变量是其他类的对象赋值 setValue: forKeyPath:
//通过键路径来给KVCClass中的对象的属性赋值
SubKVCClass *sub = [SubKVCClass new];
kvc.subKVC = sub;
[kvc setValue:@"我是subName, 通过kvc的键路径来给我赋的值" forKeyPath:@"subKVC.subName"];
NSLog(@"subName = %@", [kvc valueForKeyPath:@"subKVC.subName"]);
NSLog(@"%@", kvc);
到底什么是闭包或者block呢?用大白话说就是匿名函数
在block中可以对全局变量进行访问和修改,但对局部变量只可以访问,若想修改的话,我们可以在声明局部变量的时候加上关键字__block
-(void)test{
//定义两个变量一个是可变的一个是不可变的
NSString *str1 = @"文明"; //不可变
NSMutableString *str2 = [NSMutableString stringWithFormat:@"失灵"]; //可变
//初始值
NSLog(@"两个字符串的初始值和初始地址");
NSLog(@"str1 = %@, str1_p = %p", str1, str1);
NSLog(@"str2 = %@, str2_p = %p", str2, str2);
//定义block在block中输出连个变量的值和参数
void (^myBlock) () = ^()
{
NSLog(@"******************************************");
NSLog(@"在block块中输出局部变量的可变和不可变变量");
NSLog(@"str1 = %@, str1_p = %p", str1, str1);
NSLog(@"str2 = %@, str2_p = %p", str2, str2);
};
//修改前赋值
str1 = @"文明改变";
[str2 appendString:@"改变"];
NSLog(@"******************************************");
NSLog(@"输出修改后的值和地址");
NSLog(@"str1 = %@, str1_p = %p", str1, str1);
NSLog(@"str2 = %@, str2_p = %p", str2, str2);
//调用block
myBlock();
NSLog(@"******************************************");
NSLog(@"调用block后的值和地址");
NSLog(@"str1 = %@, str1_p = %p", str1, str1);
NSLog(@"str2 = %@, str2_p = %p", str2, str2);
}
输出:
两个字符串的初始值和初始地址
str1 = 文明, str1_p = 0x107898270
str2 = 失灵, str2_p = 0x7fb3ca518e40
******************************************
输出修改后的值和地址
str1 = 文明改变, str1_p = 0x107898350 //因为str1是不可变字符串 当其值修改了 就会产生一个新的字符串 会分配一个新的内存地址
str2 = 失灵改变, str2_p = 0x7fb3ca518e40
******************************************
在block块中输出局部变量的可变和不可变变量
str1 = 文明, str1_p = 0x107898270
str2 = 失灵改变, str2_p = 0x7fb3ca518e40
******************************************
调用block后的值和地址
str1 = 文明改变, str1_p = 0x107898350
str2 = 失灵改变, str2_p = 0x7fb3ca518e40
总结:
对值类型的修改,如果block初始化后,无法同步到block内部 因为值类型修改后 就会产生一个新的内存地址 原先的不变 所以block中还是调用原先内存地址 所以没有改变
对于引用类型的修改,如果block初始化后,修改指针指向,即指向另外一块内存,这样也是无法同步到block内部 因为指针指向另一个内存地址 原先的内存地址中的值没有改变 所以没有改变
对于引用类型的修改,如果block初始化后,对指针指向的内存进行修改,这样是可以用同步到block内部,但block内部同样无法修改。 因为没有产生新的内存地址 只是修改了原先的内存地址中的值 所以会改变。
成员变量在block中的使用是加上self->a使用的,所以在声明成员变量的时候加不加__block,在成员函数中的代码块中都可以访问修改;
@interface ViewController (){
__block NSString *hasBlock;
NSString *noBlock;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self test];
}
-(void)test{
//分别给两个成员变量赋初始值
hasBlock = @"ludashi";
noBlock = @"ludashi";
NSLog(@"hasBlock = %@, hasBlock_p = %p", hasBlock, hasBlock);
NSLog(@" noBlock = %@, noBlock_p = %p", noBlock, noBlock);
//定义block
void (^myBlock)() = ^()
{
//修改加__block的成员变量的值
hasBlock = @"ludashi_update";
NSLog(@"block中输出的内容");
NSLog(@"hasBlock = %@, hasBlock_p = %p", hasBlock, hasBlock);
NSLog(@" noBlock = %@, noBlock_p = %p", noBlock, noBlock);
};
//改变noBlock的值
noBlock = @"ludashi_update";
NSLog(@"更新后的值");
NSLog(@"hasBlock = %@, hasBlock_p = %p", hasBlock, hasBlock);
NSLog(@" noBlock = %@, noBlock_p = %p", noBlock, noBlock);
//调用block
myBlock();
//调用block后的值
NSLog(@"调用myBlock后的值");
NSLog(@"hasBlock = %@, hasBlock_p = %p", hasBlock, hasBlock);
NSLog(@" noBlock = %@, noBlock_p = %p", noBlock, noBlock);
}
输出:
hasBlock = ludashi, hasBlock_p = 0x1047b9270
noBlock = ludashi, noBlock_p = 0x1047b9270 //如果两个字符串的值相同 则这两个字符串指向同一个内存地址
更新后的值
hasBlock = ludashi, hasBlock_p = 0x1047b9270
noBlock = ludashi_update, noBlock_p = 0x1047b92d0
block中输出的内容
hasBlock = ludashi_update, hasBlock_p = 0x1047b92d0
noBlock = ludashi_update, noBlock_p = 0x1047b92d0
调用myBlock后的值
hasBlock = ludashi_update, hasBlock_p = 0x1047b92d0
noBlock = ludashi_update, noBlock_p = 0x1047b92d0
总结:对于一个、多个成员变量,不管是否用__block修饰(用不用都没任何影响),block结构体会生成一个成员 :self,并且会引用成员变量所属的对象实例 self。
那么在ARC模式下是不是意味着我们就可以一点也不用进行内存管理的呢?并不是这样的,我们还需要代码进行内存的管理。
标签:
原文地址:http://www.cnblogs.com/wwm881101/p/5466824.html