请帮助我使用基于块的回调

时间:2013-03-11 08:41:36

标签: ios objective-c ios5 ios6 objective-c-blocks

我对基于块的回调有不了解。似乎有两种我知道的方法,我不知道何时应该使用一种方法,所以有人可以向我解释两者之间的差异,纠正我并给我一些提示,如果我需要的话任何。

我发现了一些代码,我发现了stackoverflow以及来自其他地方的库,所以感谢编写此代码的人。

typedef void (^MyClickedIndexBlock)(NSInteger index);
@interface YourInterface : YourSuperClass
@property (nonatomic, strong) MyClickedIndexBlock clickedIndexBlock

.m
//where you have to call the block
if (self.clickedIndexBlock != nil) {self.clickedIndexBlock(buttonIndex)};

// where you want to receive the callback
alert.clickedIndexBlock = ^(NSInteger index){NSLog(@"%d", index);};

我对上述内容的理解是:

  1. MyClickedIndexBlock是NSInteger的typedef。使用名称“clickedIndexBlock”创建的属性,其类型为MyClickedIndexBlock(表示clickedIndexBlock可以是数字)。

  2. 块也可以用作方法,这就是为什么我可以调用self.clickedIndexBlock(buttonIndex);

  3. 但有些东西告诉我,这种作为@property的方法只支持一个参数 例如。 NSInteger的。

    鉴于以下方法允许多个参数。

    bluetoothMe.h

    typedef void (^hardwareStatusBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
    
    - (void)hardwareResponse:(hardwareStatusBlock)block;
    

    bluetoothMe.m

    - (void)hardwareResponse:(hardwareStatusBlock)block {
    privateBlock = [block copy]; 
    }
    
    - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    NSLog(@"Did connect to peripheral: %@", peripheral);
    
    privateBlock(peripheral, BLUETOOTH_STATUS_CONNECTED, nil);
    
    NSLog(@"Connected");
    [peripheral setDelegate:self];
    [peripheral discoverServices:nil];
     }
    

    我的理解是创建一个强大的属性并执行[块复制]将保留块,直到应用程序终止。所以[block copy]和强者都保留了。 [块复制]应用于块以保留,否则当方法超出范围时块将消失。

    ViewController.m

    [instance hardwareResponse:^(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error) {
    
        if (status == BLUETOOTH_STATUS_CONNECTED)
        {
            NSLog(@"connected!");
        }
        else if (status == BLUETOOTH_STATUS_FAIL_TO_CONNECT)
        {
            NSLog(@"fail to connect!");
        }
        else
        {
            NSLog(@"disconnected!");
        }
    
        NSLog(@"CBUUID: %@, ERROR: %@", (NSString *)peripheral.UUID, error.localizedDescription);
    }];
    

    让我们看看我的问题是什么:

    1)我何时会选择第一种方法而不是第二种方法,反之亦然?

    2)第一个例子,块是属性的typedef。第二个例子,块被声明为一个方法。为什么不能将第一个示例声明为方法,为什么第二个示例不能将typedef声明为属性?

    3)我是否需要为每种类型的委托方法创建一个typedef,我想要一个基于块的回调?

    4)到目前为止,我只看到了一种支持的委托方法。如果我要在多个不相似的委托方法上创建基于块的回调,你能否告诉我一个如何实现每种方法的例子?

    感谢您的反馈。这有时很难。需要尽可能多的帮助。 谢谢,

3 个答案:

答案 0 :(得分:7)

问题

  • 是否typedef阻止
  • 是否使用某个块的属性,
  • 块是否具有单个或多个参数,

完全独立(或正交)。所有组合都是 可能和允许。

void (^myClickedIndexBlock)(NSInteger index);

声明一个带有整数参数的块变量myClickedIndexBlock 并返回虚空。如果出现相同的块类型,则可以使用typedef 在您的计划中反复出现:

// Define MyClickedIndexBlock as *type* of a block taking an integer argument and returning void:
typedef void (^MyClickedIndexBlock)(NSInteger index);
// Declare myClickedIndexBlock as a *variable* of that type:
MyClickedIndexBlock myClickedIndexBlock;

有多个参数:

void (^privateBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);

typedef void (^hardwareStatusBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
hardwareStatusBlock privateBlock;

您可以使用属性代替(实例)变量。在第一个例子中:

@property (nonatomic, copy) void (^myClickedIndexBlock)(NSInteger index);

myClickedIndexBlock声明为块属性,等同于

typedef void (^MyClickedIndexBlock)(NSInteger index);
@property (nonatomic, copy) MyClickedIndexBlock clickedIndexBlock;

与您的假设相反,块属性不限于块 只有一个参数。您也可以在第二个示例中使用属性, 有或没有typedef:

@property (nonatomic, copy) void (^privateBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);

typedef void (^hardwareStatusBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
@property (nonatomic, copy) privateBlock;

您可以选择是否使用实例变量或块的属性。 我会使用属性(使用“copy”属性)。

是否键入def纯粹是一种品味问题。它有助于避免 如果在程序中重复出现相同的块类型,则会出错。在另一 手,Xcode自动完成似乎没有typedef更好(在我的 体验)。

答案 1 :(得分:3)

我强烈建议您阅读Blocks Programming Guide

块不是方法。我不会解释Conceptual Overview中所说的内容,只是引用一些部分:

  

Blocks通常代表小的,自包含的代码片段。 [...]
  它们允许您在稍后在方法实现的上下文中执行的调用时编写代码。

似乎你对语法感到困惑。

typedef void (^MyClickedIndexBlock)(NSInteger index);

它基本上只是定义一个名为 MyClickedIndexBlock 的类型,表示一个块,它接受NSInteger类型的单个参数并且不返回任何内容(void)。
它是 NSInteger的typedef。

@property (nonatomic, strong) MyClickedIndexBlock clickedIndexBlock

是包含MyClickedIndexBlock的属性声明 不需要输入def块,编写

是完全有效的
@property (nonatomic, strong) void(^clickedIndexBlock)(NSInteger index);

但为了清晰(或重复使用),您可以选择键入它们。请注意,属性名称位于^

之后

您说明可以将块用作方法,因为您可以在示例中调用self.clickedIndexBlock(buttonIndex)。但事实上,这是因为你已经声明了一个名为clickedIndexBlock的属性,你可以这样称呼它。

你的问题有很多,但很大一部分是由于混乱和误解造成的。你提到的两种方法并没有什么不同。块是对象,可以作为参数,局部变量或ivars /属性进行操作,就像使用NSString或其他类型的对象一样。

答案 2 :(得分:0)

1)该块未对整数进行typedef。它的typedef将返回void并具有整数参数。精神1或方法2没有任何优势;如果声明,它们都可以有多个参数。

2)没有理由为这两种情况选择这种格式。它们都取得了相同的结果,但第一个可以说在语义上更好。

3)否。您可以向方法声明内联块。查看[NSArray enumerateObjectsUsingBlock:]的标题,以获取内联块声明的示例。

4)您可以创建多个属性,并在必要时调用每个不同的块。