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

 

时间: 2024-11-05 00:09:17

GCD2 :在Block Object中访问变量的相关文章

如何在SSIS的脚本组件中访问变量

原文:如何在SSIS的脚本组件中访问变量 这是一个小问题,我们在SSIS的设计中很多地方都会用到变量,我习惯性地将"变量"和"表达式"称为SSIS的灵魂,虽然不见得绝对准确,但它们确实是保证一个SSIS包灵活性的根本. 同时,我们可能也会在数据流任务中添加"脚本组件",用我们熟知的C#或者VB.NET编写一些数据转换处理的逻辑.这里可能就有一个需求,我们希望在脚本组件中访问变量(读或者写),但默认情况下,这个需求并不是那么容易实现.我们来看下面的

ActionScript3.0教你在影片剪辑中访问主场景中的变量

在ActionScript2.0中,影片剪辑访问主场景中的变量非常的简单,仅仅需要用一个带有_root的绝对路径即可. 然而在ActionScript3.0影片剪辑中访问主场景中的变量却没有那么容易,使用root将会报错.下面为大家介绍一种非常简单的方法来访问主场景中的变量. 方法如下: 1.在MC(影片剪辑实例名称)里定义一个变量father:Object; 2.在主场景代码中进行赋值 MC.father = this; 3.在影片剪辑里访问的时候就直接 father.变量名 就行.

关于“在本类中访问本类私有静态变量”的一点疑惑解析

关于"在本类中访问本类私有静态变量"的一点疑惑解析 代码如下: public class StaticVar { private static int x = 100; public static void main(String[] args) { StaticVar var1 = new StaticVar(); var1.x++; StaticVar var2 = new StaticVar(); var2.x++; StaticVar.x++; System.out.print

关于在事件代码中如何访问类中的变量

事件代码访问类中变量的3种方法. 在写事件代码的时候,常常需要引用主类中的变量.要访问这些变量是需要一些技巧的. 方法一: 加上final修饰符. 1 public class HelloWorld5 { 2 public static void main(String[] args) { 3 // 在变量前加上final,否则在事件代码里不能引用. 4 final String str = "孔肖寒"; 5 6 Display display = Display.getDefault

每天一个JavaScript实例-从js脚本中访问object元素中的SVG

<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>每天一个JavaScript实例-从js脚本中访问object元素中的SVG</title> <style> </style> </head> &l

Javascript中typeof()为object类型的变量才可以添加属性

代码01:int var a = 10; a.name = "HelloWorld"; alert(a.name); 输出 undefined 代码02: string var a = "abc"; a.name = "HelloWorld"; alert(a.name); 输出 undefined 代码03: String var a = new String(); a.name = "HelloWorld"; alert(

django中模板变量与内置标签以及过滤器

本文参考 官方文档 . 一  模板变量 格式: {{ variable_name }} variable_name   命名规则与变量命名规则类似,允许字符数字下划线,不允许标点. variable_name后面可以跟dot  .  以此来访问变量的属性.查询顺序: 字典查询 属性或者方法查询: 若为方法查询,则要求该方法不需要传入任何参数.调用该方法后,会将该方法返回的结果赋予该变量. 数字索引查询 二  内置标签 格式: {% tag %} 1  block  定义一个可以被子模板覆盖的区域

OC高级编程——深入block,如何捕获变量,如何存储在堆上

首先先看几道block相关的题目 这是一篇比较长的博文,前部分是block的测试题目,中间是block的语法.特性,block讲解block内部实现和block存储位置,请读者耐心阅读.具备block基础的同学,直接调转到block的实现 下面列出了五道题,看看能否答对两三个.主要涉及block栈上.还是堆上.怎么捕获变量.答案在博文最后一行 //-----------第一道题:-------------- void exampleA() { char a = 'A'; ^{ printf("%

javascript中的变量、作用域和内存问题

[变量][1]定义:可变的量,相当于给一个不定的数据起了一个外号.变量是存储信息的容器.[2]特性:js中的变量是松散类型的,可以保存任何类型的数据.它只是在特定时间用于保存特定值的一个名字而已.由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据类型可以在脚本的生命周期内改变.[3]变量声明:变量可以在声明时赋值,但不能有其他操作,如+=.-=等 var a = 2;//是正确的 var a += 2;//是错误的 var a = 2++;//是错误的,++只能用于变量,不能