3

我对基于块的回调不了解。我似乎知道有两种方法,我不知道什么时候应该使用另一种,所以有人可以向我解释这两种方法之间的区别,纠正我并在需要时给我一些提示任何。

我从 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。以 MyClickedIndexBlock 类型的名称“clickedIndexBlock”创建的属性(意味着 clickedIndexBlock 可以是一个数字)。

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

但是有些东西告诉我,这种作为@property 的方法只真正支持一个参数,例如。NS 整数。

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

蓝牙Me.h

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

- (void)hardwareResponse:(hardwareStatusBlock)block;

蓝牙Me.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] 和 strong 都保留。[块复制] 应用于块以保留,否则当方法超出范围时块将消失。

视图控制器.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?

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

4) 迄今为止,我只看到支持一种委托方法。如果我要在多个不相似的委托方法上创建基于块的回调,您能否向我展示一个如何实现每种方法的示例。

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

4

3 回答 3

7

问题

  • 不管是typedef不是阻塞,
  • 是否将属性用于块,
  • 一个块是否有一个或多个参数,

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

void (^myClickedIndexBlock)(NSInteger index);

声明一个myClickedIndexBlock采用整数参数并返回 void 的块变量。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;

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

是否 typedef 纯粹是个人喜好问题。如果您的程序中重复出现相同的块类型,这有助于避免错误。另一方面,Xcode 自动补全似乎在没有 typedef 的情况下工作得更好(根据我的经验)。

于 2013-03-11T09:51:07.247 回答
3

我强烈建议您阅读Blocks Programming Guide

块不是方法。我不打算解释概念概述中所说的内容,而只是引用一些部分:

块通常代表小的、独立的代码片段。[...]
它们允许您在调用点编写代码,稍后在方法实现的上下文中执行。

您似乎对语法感到困惑。

typedef void (^MyClickedIndexBlock)(NSInteger index);

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

@property (nonatomic, strong) MyClickedIndexBlock clickedIndexBlock

是一个将包含 MyClickedIndexBlock 的属性的声明。
不需要 typedef 块,编写它是完全有效的

@property (nonatomic, strong) void(^clickedIndexBlock)(NSInteger index);

但为了清楚起见(或重用),您可以选择对它们进行 typedef。请注意,属性名称是^.

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

你的问题有很多,但很大一部分是由于混淆和误解。您提到的两种方法并没有真正的不同。块是对象,可以像处理 NSString 或其他类型的对象一样作为参数、局部变量或 ivars / 属性进行操作。

于 2013-03-11T09:51:53.380 回答
0

1)该块不是类型定义为整数。它是 typedef 的返回 void 并且有一个整数参数。精神 1 或方法 2 没有优势;如果声明它们都可以有多个参数。

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

3) 不可以。您可以将块内联声明到方法中。查看标题以[NSArray enumerateObjectsUsingBlock:]获取内联块声明的示例。

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

于 2013-03-11T09:55:08.603 回答