Danh sách cú pháp khai báo khối


277

Cú pháp chặn trong Mục tiêu C (và thực sự là C, tôi đoán là) không phổ biến. Truyền các khối làm đối số trông khác với khai báo các khối là ngà, trông khác với typedefkhối ing.

Có một danh sách đầy đủ các cú pháp khai báo khối mà tôi có thể giữ trong tay để tham khảo nhanh không?


9
Có gì sai với "Khai báo và tạo khối" trong Hướng dẫn chủ đề lập trình khối?
jscs

giải thích đơn giản về việc sử dụng các thuộc tính khối: stackoverflow.com/a/20760583/294884
Fattie

Câu trả lời:


696

Danh sách các cú pháp khai báo khối

Trong suốt, hãy

  • return_typelà loại đối tượng / nguyên thủy / vv. bạn muốn quay lại (thông thường void)
  • blockName là tên biến của khối bạn đang tạo
  • var_typelà loại đối tượng / nguyên thủy / vv. bạn muốn chuyển qua làm đối số (để trống không có tham số)
  • varName là tên biến của tham số đã cho

Và hãy nhớ rằng bạn có thể tạo bao nhiêu tham số tùy thích.

Khối như biến

Có thể là phổ biến nhất cho khai báo.

return_type (^blockName)(var_type) = ^return_type (var_type varName)
{
    // ...
};

Khối là thuộc tính

Giống như khai báo các khối như các biến, tuy nhiên khác nhau một cách tinh tế.

@property (copy) return_type (^blockName) (var_type);

Khối làm tham số

Lưu ý rằng điều này khác với "Khối như đối số"; trong trường hợp này, bạn đang khai báo một phương thức muốn có một đối số khối.

- (void)yourMethod:(return_type (^)(var_type))blockName;

Khối như đối số

Lưu ý rằng điều này khác với "Khối như tham số"; trong trường hợp này, bạn đang gọi một phương thức muốn có một đối số khối với một khối ẩn danh. Nếu bạn đã khai báo một biến khối, việc truyền tên biến làm đối số là đủ.

[someObject doSomethingWithBlock: ^return_type (var_type varName)
{
    //...
}];

Khối ẩn danh

Đây thực chất là một khối ẩn danh, tuy nhiên cú pháp gán các khối cho các biến chỉ đơn giản là đặt biến bằng với một khối ẩn danh.

^return_type (var_type varName)
{
    //...
};

typedef Khối

Điều này cho phép bạn thiết lập một tên ngắn có thể được tham chiếu giống như bất kỳ tên lớp nào khác trong quá trình khai báo các khối.

typedef return_type (^blockName)(var_type);

Để sau đó sử dụng blockNamethay vì cú pháp khai báo khối tiêu chuẩn, chỉ cần thay thế.

Chặn Nội tuyến

Đây được cho là việc sử dụng các khối ít hữu ích hơn, nhưng dù sao cũng có thể có vị trí của nó. Một khối nội tuyến là một khối ẩn danh được gọi ngay sau khi khởi tạo.

^return_type (var_type varName)
{
    //...
}(var);

Các khối nội tuyến chủ yếu hữu ích cho việc bù đắp phạm vi và gần tương đương với các đoạn mã được phân định bằng dấu ngoặc đơn giản.

{
   //...
}

Khối đệ quy

Điều này cho phép bạn gọi một khối từ chính nó, tạo ra một vòng lặp có thể được sử dụng trong các cuộc gọi lại và các cuộc gọi GCD. Phương pháp khởi tạo này không có chu kỳ giữ lại trong ARC.

__block return_type (^blockName)(var_type) = [^return_type (var_type varName)
{
    if (returnCondition)
    {
        blockName = nil;
        return;
    }

    // ...
} copy];
blockName(varValue);

Khối trở về

Một phương thức có thể trả về một khối,

- (return_type(^)(var_type))methodName
{
    // ...
}

như một chức năng có thể, nếu một chút lạ lùng.

return_type (^FunctionName())(var_type)
{
    // ...
}

Phụ lục

Nếu tôi bỏ lỡ bất cứ điều gì, xin vui lòng cho tôi biết trong các nhận xét và tôi sẽ nghiên cứu / thêm chúng.

Ồ, và trong Swift ...

blockName = (varName: var_type) -> (return_type)

Nó gần giống như đó là một tính năng ngôn ngữ.


1
@pcperini Một danh sách tuyệt vời! Và làm thế nào để sử dụng định nghĩa khối typedef'd trong khai báo biến (mục đầu tiên trong danh sách của bạn)? Logic BlockType ^blockVar = Anonymous Blockhiển thị lỗi cú pháp, không có ^ quá :(
đặc biệt là

14
Bằng cách nào đó bộ não của tôi không có khả năng ghi nhớ tất cả các cú pháp khác nhau này để khai báo khối. Tôi có thể nhìn vào câu trả lời này mỗi tuần một lần. Ước gì tôi có thể cung cấp cho bạn 10 upvote cho việc này.
Ben Baron

36
Chúng tôi cần một Hall of Fame StackOverflow cho câu trả lời như thế này.
bejonbee

1
Tôi đã chuyển đổi nó thành Markdown để sử dụng với trình xem để in. Tiện dụng! gist.github.com/swizzlr/6268955
Swizzlr

20
Tôi nghĩ rằng tôi cần điều này như một hình xăm.
Isaac Overacker


39

Typedef:

typedef void (^block)(NSString *arg);

Nội tuyến:

void (^block)(NSString *) = ^(NSString *param) {
  // do something....
};

Phương pháp:

- (void)method:(void (^)(NSString *param))handler

Câu trả lời này cho thấy rằng nó không quá phức tạp sau tất cả ... chỉ 3 cú pháp khác nhau để trộn và khớp.
Joseph Chen

4
Câu trả lời được chấp nhận chỉ là một bản sao của câu trả lời này với sự phình to không cần thiết.
Erik Aigner

16

Thư viện đoạn mã Xcode 4 chứa các mẫu cho các khối typedefs và các khối nội tuyến dưới dạng các biến. Chúng cũng có sẵn thông qua tự động hoàn thành ( typedefblockinlineblock).

Đối với các khối làm đối số cho các phương thức, tôi khuyên bạn nên khai báo a typedefvà sau đó chỉ cần sử dụng điều đó. Nó làm cho mã dễ đọc hơn nhiều.


11

Tôi đã viết xongBlock cho một lớp sẽ trả về các giá trị của xúc xắc sau khi chúng bị lắc:

  1. Xác định typedef với returnType ( khai báo .hở trên @interface)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue);
  2. Xác định a @propertycho khối ( .h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
  3. Xác định một phương thức với finishBlock( .h)

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
  4. Chèn phương pháp được xác định trước đó trong .mtập tin và cam kết finishBlockđể @propertyđược xác định trước

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
  5. Để kích hoạt completionBlockvượt qua biếnType được xác định trước cho nó (Đừng quên kiểm tra xem có completionBlocktồn tại không)

    if( self.completeDiceRolling ){
        self.completeDiceRolling(self.dieValue);
    }

7
typedef void (^OkBtnBlock)(id data);
typedef void (^CancelBtnBlock)();

@property (nonatomic, strong) OkBtnBlock okBtnBlock;
@property (nonatomic, strong) CancelBtnBlock cancelBtnBlock;

+ (void)foo:(OkBtnBlock)okBtn andCancel:(CancelBtnBlock)btnCancel;

Sẽ rất tốt để mô tả toàn bộ quá trình từng bước một, các khối rất khó hiểu nếu bạn chưa quen với ios ...
Alex Cio

3

Nếu bạn cần làm việc trở lại trong Xcode 4.2, bạn cũng có thể @synthesize một khối được khai báo là thuộc tính giống như bạn làm với thuộc tính không chặn. Đừng để cú pháp khối ném bạn.

Nếu thuộc tính khối của bạn là:

@property (copy) return_type (^blockName) (var_type);

Sau đó, @synthesize của bạn là thế này:

@property blockName;

Chúc mừng.


Xin chào, bạn có thể vui lòng kiểm tra lại không .. Tôi chỉ đang cố gắng theo dõi bạn .. @property blockNamekhông hoạt động. Tôi nghĩ nó nên @synthesize blockName;? (để tổng hợp một khối)
jeet.chanchaw

Rất tiếc ... chờ bạn đã (gián tiếp) đề cập rằng nó sẽ không hoạt động với xcode 7.
jeet.chanchaw
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.