6

Tôi có một chỉ đọc tài sản isFinished trong file giao diện của tôi:Chuyển nhượng để Ivar trong một khối thông qua con trỏ yếu

typedef void (^MyFinishedBlock)(BOOL success, NSError *e); 

@interface TMSyncBase : NSObject { 
    BOOL isFinished_; 
} 

@property (nonatomic, readonly) BOOL isFinished; 

và tôi muốn đặt nó vào YES trong một khối tại một số điểm sau, mà không cần tạo một chu kỳ giữ chân đến self:

- (void)doSomethingWithFinishedBlock:(MyFinishedBlock)theFinishedBlock { 
    __weak MyClass *weakSelf = self; 
    MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { 
     [weakSelf willChangeValueForKey:@"isFinished"]; 
     weakSelf -> isFinished_ = YES; 
     [weakSelf didChangeValueForKey:@"isFinished"]; 
     theFinishedBlock(success, e); 
    }; 

    self.finishedBlock = finishedBlockWrapper; // finishedBlock is a class ext. property 
} 

Tôi không chắc chắn đây là cách phù hợp để thực hiện. Mã này có bị rò rỉ hoặc bị hỏng hay không? Có lẽ có một cách dễ dàng hơn tôi đã bỏ qua?

+2

chỉ cần fyi, bạn có thể sử dụng '__weak typeof (self) * weakSelf = self;' –

+0

tuyệt, hữu ích! – manmal

+4

Chỉnh sửa nhỏ cho khai báo chung '__weak typeof (self) weakSelf = self;' typeof (self) đã là một con trỏ. – allprog

Trả lời

5

Đi qua biến khối có thể bằng không, kiểm tra trước khi gọi điện thoại hoặc thêm khẳng định về sự khởi đầu của hàm hoặc bạn sẽ sụp đổ

Vì bạn đang không giữ lại bản thân và chúng tôi giả định rằng bạn thực hiện một số nhiệm vụ dài trên sợi nền bởi thời gian mã của bạn có được thực hiện weakSelf có thể là nil (hy vọng bạn đang sử dụng ARC và 5.0, do đó bạn có tài liệu tham khảo yếu niled).

Nếu bạn không có tài liệu tham khảo thực sự yếu (< 5.0, không có ARC, trình biên dịch sẽ vẫn chấp nhận __weak nhưng nó sẽ không quan trọng) điều này sẽ dẫn đến sự cố.

Cũng truy cập ivar bằng cách sử dụng '->' sẽ dẫn đến sự cố nếu đối tượng con trỏ là 0, do đó bạn cần đảm bảo rằng nó không xảy ra.

Thậm chí nếu bạn làm mã như dasblinkenlight đã viết nó có thể sụp đổ nếu weakSelf sẽ là nil tại thời điểm này, giả sử bạn gửi khối trên chủ đề nền và sau đó đối tượng được phát hành trước khi thực hiện khối, điều này làm cho weakSelf nil do đó accesing nó bằng cách sử dụng '->' sẽ dẫn đến sự cố. Trong trường hợp đó, tôi sẽ sửa đổi mã như sau:

__weak MyClass *weakSelf = self; 
MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { 
    MyClass *strongSelf = weakSelf; 
    //! whatever task you want executed 
    strongSelf.isFinished = YES; 
    theFinishedBlock(success, e); 
}; 

Ngoài ra, bạn cũng không thể ngăn tác vụ tốn kém thực hiện nếu không có ý nghĩa (đối tượng đã bị hủy). Nhưng điều này phụ thuộc vào trường hợp sử dụng. Tuy nhiên, cũng có trường hợp khác bạn cần xem xét khi lập trình với các khối, ví dụ: Bạn có thể có một đối tượng công việc chỉ là vai trò thực hiện một số tác vụ trong nền, trong trường hợp đó mã này có thể thất bại vì bạn sẽ tạo ra nhiệm vụ mới và nó có thể được deallocated trước khi khối thực hiện trên nền thread, trong trường hợp đó bạn nên giữ lại bản thân và không giữ lại khối trong đối tượng (điều này sẽ ngăn chặn giữ chu kỳ).

+0

cảm ơn! Vâng, đó là iOS5, cảm ơn lòng tốt. – manmal

+0

isFinished là một thuộc tính chỉ đọc, vì vậy tôi không muốn '' 'strongSelf.isFinished = YES''' để làm việc .. nó chỉ có cho KVO – manmal

+1

Chỉ định là một gán bình thường trong thể loại tư nhân, điều này sẽ làm cho nó làm isFinished ghi trong mã lớp của bạn nhưng chỉ đọc bên ngoài nó, điều này cũng sẽ bỏ qua các thông báo KVO thủ công không cần thiết. –

0

Cách giải quyết nhẹ là tạo phương thức và để trình biên dịch xử lý nó cho bạn. Hoạt động tốt, nhưng tôi không chắc chắn nếu nó là cách chính xác. Ai đó có thể cho biết nếu nó chính xác?

__weak MyClass *weakSelf = self; 
MyFinishedBlock finishedBlockWrapper = ^(BOOL success, NSError *e) { 
    [weakSelf makeIsFinishedYes]; 
}; 

- (void)makeIsFinishedYes 
{ 
    isFinished_ = YES; 
} 
Các vấn đề liên quan