GCD2 :在Block Object中访问变量

问题:

你想要理解在 Objective-C 方法和在 Block Objects 中访问变量的区别 

 方案:

这儿简单总结一下关于 Block Objects 变量你需要知道的内容:
1.局部变量在 Block Objects 和 Objective-C 方法中的工作原理非常相似。
 
2.对于内联Block Objects,局部变量不仅包含Block内部定义的变量,并且包含在Block Objects 执行方法中定义的变量。(随后会有举例)

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.

如何在两个 Block Objects 的执行过程中使用变量;一个是内联 Block Object,另一个是独立 Block Objects :

 

 

- (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;
    }];
}
Block Object 可以读写它自己的 insideVariable 局部变量。然而,对于默认的 outsideVariable 变量,Block Object 只能读不能写。 
 
为了允许 Block Object 写入 outsideVariable,我们必须给 outside Variable 增加一个__block 存储类的前缀: 
- (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;
    }];
}
 
独立 Block Objects不能直接访问self...
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.

内联 Block Objects 在其词法区域会对变量的值进行拷贝。 
如果不明白这一点,不要担心,我们看个例子: 
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

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2014-10-29 10:26  safiri  阅读(303)  评论(0编辑  收藏  举报