Làm thế nào để thực hiện các chức năng gọi lại trong Objective-C?
Tôi chỉ muốn xem một số ví dụ đã hoàn thành và tôi nên hiểu nó.
Làm thế nào để thực hiện các chức năng gọi lại trong Objective-C?
Tôi chỉ muốn xem một số ví dụ đã hoàn thành và tôi nên hiểu nó.
Câu trả lời:
Thông thường, các lệnh gọi lại trong mục tiêu C được thực hiện với các đại biểu. Đây là một ví dụ về triển khai ủy quyền tùy chỉnh;
Tập tin tiêu đề:
@interface MyClass : NSObject {
id delegate;
}
- (void)setDelegate:(id)delegate;
- (void)doSomething;
@end
@interface NSObject(MyDelegateMethods)
- (void)myClassWillDoSomething:(MyClass *)myClass;
- (void)myClassDidDoSomething:(MyClass *)myClass;
@end
Thực hiện (.m) Tệp
@implementation MyClass
- (void)setDelegate:(id)aDelegate {
delegate = aDelegate; /// Not retained
}
- (void)doSomething {
[delegate myClassWillDoSomething:self];
/* DO SOMETHING */
[delegate myClassDidDoSomething:self];
}
@end
Điều đó minh họa cách tiếp cận chung. Bạn tạo một danh mục trên NSObject khai báo tên của các phương thức gọi lại của bạn. NSObject không thực sự triển khai các phương pháp này. Loại danh mục này được gọi là giao thức không chính thức, bạn chỉ đang nói rằng nhiều đối tượng có thể triển khai các phương thức này. Chúng là một cách để chuyển tiếp khai báo kiểu chữ ký của bộ chọn.
Tiếp theo, bạn có một số đối tượng là đại biểu của "MyClass" và MyClass gọi các phương thức đại biểu trên đại biểu nếu thích hợp. Nếu các lệnh gọi lại được ủy quyền của bạn là tùy chọn, thông thường bạn sẽ bảo vệ chúng tại trang điều phối bằng một cái gì đó như "if ([Delegate responseToSelector: @selector (myClassWillDoSomething :)) {". Trong ví dụ của tôi, người được ủy quyền được yêu cầu triển khai cả hai phương pháp.
Thay vì một giao thức không chính thức, bạn cũng có thể sử dụng một giao thức chính thức được xác định bằng @protocol. Nếu bạn làm điều đó, bạn sẽ thay đổi kiểu của trình thiết lập ủy quyền và biến thể hiện thành " id <MyClassDelegate>
" thay vì chỉ " id
".
Ngoài ra, bạn sẽ nhận thấy người đại diện không được giữ lại. Điều này thường được thực hiện vì đối tượng "sở hữu" các thể hiện của "MyClass" thường cũng là đại biểu. Nếu MyClass giữ lại đại biểu của nó, thì sẽ có một chu kỳ lưu giữ. Đó là một ý tưởng hay trong phương thức dealloc của một lớp có thể hiện MyClass và là đại diện của nó để xóa tham chiếu đại biểu đó vì nó là một con trỏ ngược yếu. Nếu không, nếu có điều gì đó đang giữ cho cá thể MyClass tồn tại, bạn sẽ có một con trỏ treo lơ lửng.
Để hoàn thiện, vì StackOverflow RSS vừa ngẫu nhiên trả lại câu hỏi cho tôi, nên tùy chọn khác (mới hơn) là sử dụng các khối:
@interface MyClass: NSObject
{
void (^_completionHandler)(int someParameter);
}
- (void) doSomethingWithCompletionHandler:(void(^)(int))handler;
@end
@implementation MyClass
- (void) doSomethingWithCompletionHandler:(void(^)(int))handler
{
// NOTE: copying is very important if you'll call the callback asynchronously,
// even with garbage collection!
_completionHandler = [handler copy];
// Do stuff, possibly asynchronously...
int result = 5 + 3;
// Call completion handler.
_completionHandler(result);
// Clean up.
[_completionHandler release];
_completionHandler = nil;
}
@end
...
MyClass *foo = [[MyClass alloc] init];
int x = 2;
[foo doSomethingWithCompletionHandler:^(int result){
// Prints 10
NSLog(@"%i", x + result);
}];
Đây là một ví dụ giúp loại bỏ các khái niệm về đại diện và chỉ thực hiện một cuộc gọi thô trở lại.
@interface Foo : NSObject {
}
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector;
@end
@interface Bar : NSObject {
}
@end
@implementation Foo
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector {
/* do lots of stuff */
[object performSelector:selector withObject:self];
}
@end
@implementation Bar
- (void)aMethod {
Foo *foo = [[[Foo alloc] init] autorelease];
[foo doSomethingAndNotifyObject:self withSelector:@selector(fooIsDone:)];
}
- (void)fooIsDone:(id)sender {
NSLog(@"Foo Is Done!");
}
@end
Thông thường, phương thức - [Foo doSomethingAndNotifyObject: withSelector:] sẽ không đồng bộ, điều này sẽ làm cho lệnh gọi lại hữu ích hơn ở đây.
Để giữ cho câu hỏi này được cập nhật, việc giới thiệu ARC của iOS 5.0 có nghĩa là điều này có thể đạt được bằng cách sử dụng Blocks ngắn gọn hơn:
@interface Robot: NSObject
+ (void)sayHi:(void(^)(NSString *))callback;
@end
@implementation Robot
+ (void)sayHi:(void(^)(NSString *))callback {
// Return a message to the callback
callback(@"Hello to you too!");
}
@end
[Robot sayHi:^(NSString *reply){
NSLog(@"%@", reply);
}];
Luôn có F **** ng Cú pháp Khối nếu bạn quên cú pháp Khối của Objective-C.
+ (void)sayHi:(void(^)(NSString *reply))callback;
không+ (void)sayHi:(void(^)(NSString *))callback;
- (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;
(Lưu ý parameterTypes
không parameters
)
CallBack: Có 4 kiểu gọi lại trong Mục tiêu C
Loại bộ chọn : Bạn có thể xem NSTimer, UIPangesture là các ví dụ về gọi lại Bộ chọn. Được sử dụng để thực thi mã rất hạn chế.
Loại ủy quyền : Phổ biến và được sử dụng nhiều nhất trong Apple framework. UITableViewDelegate, NSNURLConnectionDelegate. Chúng thường được sử dụng để hiển thị Tải xuống nhiều hình ảnh từ máy chủ không đồng bộ, v.v.
Xin vui lòng cho tôi nếu bất kỳ câu trả lời khác cho nó. Tôi sẽ đánh giá cao nó.