GCD2 :在Block Object中访问变量
问题:
方案:
1.局部变量在 Block Objects 和 Objective-C 方法中的工作原理非常相似。
3.在 Objective-C 类中运行的独立 Block Objects 中你不能直接使用 self;如果你需要访问 self, 就必须把 Object 作为参数传递到
BlockObject,我们很快会看到举例。
4.只有当self出现在创建Block Object的词法范围内,你可以在内联Block Object内直接使用 self。
5.对于内联 Block Objects,那些在 BlockObject 执行过程中定义的局部变量是可读写的,换句话说,对于 Block Objects 自身的局部变量来说,可以对其读写。
6.对于内联 Block Objects,实现 Object 的 Objective-C 方法的局部变量只能从中读取, 不能写入。不过还有一个例外,如果定义它们通过 __block 存储类型定义的话,Block Object 可以写入此类的变量。对此我们也会有举例。
7.假设你有一个类 NSObject 的 Object,并且在这个 Object 的执行中你使用了一个Block Object与GCD相连,那么在这个Block Object内部,你会有一个存储来读取那个支持你的 Block 执行的 NSObject 内部的声明属性。
8.只有当你使用声明属性的 setter and getter 方法你才能获取独立 Block Objects 内部的NSObject 的这些属性;在一个独立 Block Object 使用“.”符号你无法获取一个 Object 的声明属性。
讨论:
1.
- (void)simpleMethod{ NSUInteger outsideVariable = 10; NSMutableArray *array = [[NSMutableArray alloc]initWithObjects:@"obj1",@"obj2", nil]; [array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { NSUInteger insideVariable = 20; NSLog(@"Outside variable = %lu",(unsigned long)outsideVariable); NSLog(@"Inside variable = %lu", (unsigned long)insideVariable); /* Return value for the block object */ return NSOrderedSame; }]; }
- (void)simpleMethod{ __block NSUInteger outsideVariable = 10; NSMutableArray *array = [[NSMutableArray alloc]initWithObjects:@"obj1",@"obj2", nil]; [array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { outsideVariable = 30; NSUInteger insideVariable = 20; NSLog(@"Outside variable = %lu",(unsigned long)outsideVariable); NSLog(@"Inside variable = %lu", (unsigned long)insideVariable); /* Return value for the block object */ return NSOrderedSame; }]; }
2.
在内联 block 中访问 self 是可行的,这跟在内联 block 中创建的对象一样。例如,在这个例子中,Block Object 将会访问 self,因为 simpleMethod 是一个 Objective-C 类的实例:
- (void)simpleMethod2{ NSMutableArray *array = [[NSMutableArray alloc]initWithObjects:@"obj1",@"obj2", nil]; [array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { NSLog(@"self = %@",self); return NSOrderedSame; }]; }
void (^incorrectBlockObject)(void) = ^{ NSLog(@"self = %@", self); /* self is undefined here */
};
编译时出现错误....
如果你想从独立 Block Objects 中访问 self,只要简单的将 self 以参数的方式传递到 block 中即可:
void (^incorrectBlockObject)(id) = ^(id self){ NSLog(@"self = %@",self); };
3.Block与已声明的属性
在内联Block Objects中,可以直接使用“.”符号读写 self 已声明属性。
[array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { NSLog(@"self = %@", self); self.stringProperty = @"Block Objects"; NSLog(@"String property = %@", self.stringProperty); /* Return value for the block object */ return NSOrderedSame; }];
而在独立Block Object 内部,你不能使用“.”符号读写一个已声明属性.
此时可以使用这个合成属性的 getter and setter 方法来代替“.”符号:
incorrectBlockObject(self);
void (^incorrectBlockObject)(id) = ^(id self){ NSLog(@"self = %@",self); //self.stringProperty = @"Block"; 独立block不能直接用点语法读写属性 [self setStringProperty:@"Block Objects"]; NSLog(@"self.stringProperty = %@",[self stringProperty]); };
4.
typedef void(^BlockWithNoParams)(void);
- (void)scopeTest{ NSUInteger integerValue = 10; /********** Definition(定义) of internal block object ***********/ BlockWithNoParams myBlock = ^{ NSLog(@"Integer value inside the block = %lu",(unsigned long)integerValue); }; /*************** End definition of internal block object ************/ integerValue = 20; /* Call the block here after changing the value of the integerValue variable */ NSLog(@"Integer value outside the block = %lu", (unsigned long)integerValue); myBlock(); }
控制台输出为:
Integer value outside the block = 20
Integer value inside the block = 10
为什么输出结果是这样呢: 我们在实现Block Object时对integerValue进行了拷贝
如果要改变这个现象呢?
方法是,我们要在需要修改的变量前加上__block前缀:
- (void)scopeTest{ __block NSUInteger integerValue = 10; /********** Definition(定义) of internal block object ***********/ BlockWithNoParams myBlock = ^{ NSLog(@"Integer value inside the block = %lu",(unsigned long)integerValue); }; /*************** End definition of internal block object ************/ integerValue = 20; /* Call the block here after changing the value of the integerValue variable */ NSLog(@"Integer value outside the block = %lu", (unsigned long)integerValue); myBlock(); }
输出为
Integer value outside the block = 20
Integer value inside the block = 20