Objective-C'de Callbacks nasıl yapılır


119

Objective-C'de geri arama işlevleri nasıl gerçekleştirilir?

Sadece tamamlanmış bazı örnekler görmek istiyorum ve bunu anlamalıyım.

Yanıtlar:


94

Normalde, C hedefindeki geri aramalar delegelerle yapılır. İşte özel bir temsilci uygulamasına bir örnek;


Başlık dosyası:

@interface MyClass : NSObject {
    id delegate;
}
- (void)setDelegate:(id)delegate;
- (void)doSomething;
@end

@interface NSObject(MyDelegateMethods)
- (void)myClassWillDoSomething:(MyClass *)myClass;
- (void)myClassDidDoSomething:(MyClass *)myClass;
@end

Uygulama (.m) Dosyası

@implementation MyClass
- (void)setDelegate:(id)aDelegate {
    delegate = aDelegate; /// Not retained
}

- (void)doSomething {
    [delegate myClassWillDoSomething:self];
    /* DO SOMETHING */
    [delegate myClassDidDoSomething:self];
}
@end

Bu, genel yaklaşımı göstermektedir. NSObject üzerinde, geri arama yöntemlerinizin adlarını bildiren bir kategori oluşturursunuz. NSObject aslında bu yöntemleri uygulamaz. Bu tür kategoriye gayri resmi protokol denir, sadece birçok nesnenin bu yöntemleri uygulayabileceğini söylüyorsunuz. Seçicinin tip imzasını bildirmenin bir yolu.

Daha sonra, "MyClass" ın temsilcisi olacak bir nesneniz var ve MyClass, uygun şekilde temsilci üzerindeki temsilci yöntemlerini çağırıyor. Temsilci geri aramalarınız isteğe bağlıysa, onları genellikle gönderim sitesinde "if ([delegate responsesToSelector: @selector (myClassWillDoSomething :)) {" gibi bir şeyle koruyacaksınız. Örneğimde, temsilcinin her iki yöntemi de uygulaması gerekir.

Resmi olmayan bir protokol yerine, @protocol ile tanımlanan resmi bir protokolü de kullanabilirsiniz. Bunu yaparsanız, temsilci belirleyicinin türünü ve örnek değişkenini id <MyClassDelegate>yalnızca " id" yerine " " olarak değiştirirsiniz.

Ayrıca, temsilcinin alıkonulmadığını fark edeceksiniz. Bu genellikle yapılır çünkü "MyClass" örneklerine "sahip" olan nesne aynı zamanda temsilci de olur. MyClass temsilcisini elinde tutarsa, o zaman bir saklama döngüsü olacaktır. MyClass örneğine sahip bir sınıfın dealloc yönteminde iyi bir fikirdir ve zayıf bir arka işaretçi olduğu için bu temsilci başvurusunu temizlemek için temsilcisidir. Aksi takdirde, MyClass örneğini canlı tutan bir şey varsa, sarkan bir işaretçiniz olur.


+1 İyi kapsamlı yanıt. Pastanın üzerine krema yapmak, delegeler hakkında daha derinlemesine Apple belgelerine bir bağlantı olacaktır. :-)
Quinn Taylor

Jon, yardımın için çok teşekkürler. Yardımın için sağol. Bunun için üzgünüm ama cevap konusunda çok net değilim. İleti .m, doSomething işlevi çağrısı sırasında kendisini temsilci olarak ayarlayan bir sınıftır. DoSomething, kullanıcının çağırdığı geri arama işlevi mi? çünkü kullanıcının doSomething'i çağırdığı ve sizin geri arama işlevlerinizin myClassWillDoSomethingg & myClassDidDoSomething olduğu izlenimi altında olduğum için. Ayrıca, geri arama işlevini çağıran daha yüksek bir sınıfın nasıl oluşturulacağını bana gösterebilir misiniz? Ben bir C programcısıyım, bu yüzden henüz Obj-C ortamına çok aşina değilim.
ReachConnection

"İleti .m", .m dosyanızdaki anlamına gelir. Ayrı bir sınıfınız olur, buna "Foo" diyelim. Foo'nun bir "Sınıfım * sınıfım" değişkeni olur ve bir noktada Foo "[sınıfım setDelegate: öz]" derdi. Bundan sonraki herhangi bir noktada, foo dahil herhangi biri MyClass'ın bu örneğinde doSomethingMethod'u çağırırsa, foo'nun myClassWillDoSomething ve myClassDidDoSomething yöntemleri çağrılırdı. Aslında, delege kullanmayan ikinci bir farklı örnek de göndereceğim.
Jon Hess

.M'nin "mesaj" anlamına geldiğini sanmıyorum.
Chuck


140

Eksiksizlik açısından, StackOverflow RSS soruyu benim için rastgele yeniden dirilttiğinden, diğer (daha yeni) seçenek blokları kullanmaktır:

@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);
}];

2
@Ahruman: "void (^ _completionHandler) (int someParameter)" daki "^" - karakteri ne yapar; anlamına gelmek? Bu satırın ne yaptığını açıklayabilir misin?
Konrad Höffner

2
Geri arama işleyicisini neden kopyalamanız gerektiğine dair bir açıklama yapabilir misiniz?
Elliot Chance

52

Temsilcilerin kavramlarını dışarıda tutan ve sadece ham bir geri arama yapan bir örnek.

@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

Tipik olarak - [Foo doSomethingAndNotifyObject: withSelector:] yöntemi, geri aramayı burada olduğundan daha kullanışlı hale getirecek şekilde zaman uyumsuz olacaktır.


1
Çok teşekkürler John. Yorumlarınızdan sonra ilk geri arama uygulamanızı anlıyorum. Ayrıca, 2. geri arama uygulamanız daha basittir. İkisi de çok iyi.
ReachConnection

1
Bu Jon'u gönderdiğiniz için teşekkürler, çok yardımcı oldu. [Object performSelectorwithObject: self] 'i değiştirmek zorunda kaldım; [object performSelector: selector withObject: self]; doğru çalışmasını sağlamak için.
Banjer

16

Bu soruyu güncel tutmak için, iOS 5.0'ın ARC'yi tanıtması, bunun Blocks kullanılarak daha da kısaca elde edilebileceği anlamına geliyor :

@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);
}];

Objective-C'nin Blok sözdizimini unutursanız her zaman F **** ng Blok Sözdizimi vardır .


@İnterface olmalıdır + (void)sayHi:(void(^)(NSString *reply))callback;değil+ (void)sayHi:(void(^)(NSString *))callback;
Tim007

Yukarıda belirtilen F **** ng Blok Sözdizimine göre değil : - (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;(Not parameterTypesdeğil parameters)
Ryan Brodie

4

CallBack: Objective C'de 4 tür geri arama vardır

  1. Seçici türü : NSTimer, UIPangesture'ın Selector geri aramasının örnekleri olduğunu görebilirsiniz. Çok sınırlı kod yürütülmesi için kullanılır.

  2. Temsilci Türü : Yaygın ve en çok Apple çerçevesinde kullanılır. UITableViewDelegate, NSNURLConnectionDelegate. Genellikle birçok görüntünün sunucudan eşzamansız olarak indirilmesini vb. Göstermek için kullanılırlar.

  3. NSNotifications : NotificationCenter, olay meydana geldiğinde birçok alıcıyı bilgilendirmek için kullanılan Objective C özelliklerinden biridir.
  4. Bloklar : Bloklar daha yaygın olarak Objective C programlamasında kullanılır. Harika bir özelliktir ve kod yığınını yürütmek için kullanılır. Ayrıca anlamak için eğiticiye başvurabilirsiniz: Bloklar eğitimi

Lütfen başka bir cevap varsa bana izin verin. Takdir edeceğim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.