Objective-C에서 콜백을 수행하는 방법


119

Objective-C에서 콜백 기능을 수행하는 방법은 무엇입니까?

완성 된 몇 가지 예제를보고 싶습니다. 이해해야합니다.

답변:


94

일반적으로 목표 C의 콜백은 델리게이트로 수행됩니다. 다음은 사용자 지정 대리자 구현의 예입니다.


헤더 파일 :

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

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

구현 (.m) 파일

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

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

이것은 일반적인 접근 방식을 보여줍니다. 콜백 메서드의 이름을 선언하는 NSObject에 범주를 만듭니다. NSObject는 실제로 이러한 메서드를 구현하지 않습니다. 이러한 유형의 범주를 비공식 프로토콜이라고합니다. 많은 개체가 이러한 메서드를 구현할 수 있다는 의미입니다. 선택 자의 형식 서명을 전달하는 방법입니다.

다음으로 일부 개체는 "MyClass"의 대리자가되고 MyClass는 대리자의 대리자 메서드를 적절하게 호출합니다. 델리게이트 콜백이 선택 사항 인 경우 일반적으로 "if ([delegate respondsToSelector : @selector (myClassWillDoSomething :)) {"과 같이 디스패치 사이트에서이를 보호합니다. 내 예에서 대리자는 두 메서드를 모두 구현해야합니다.

비공식 프로토콜 대신 @protocol로 정의 된 공식 프로토콜을 사용할 수도 있습니다. 그렇게하면 델리게이트 setter의 유형을 변경하고 인스턴스 변수를 " id <MyClassDelegate>"대신 " id"로 변경합니다.

또한 대리인이 유지되지 않음을 알 수 있습니다. 이는 일반적으로 "MyClass"인스턴스를 "소유"하는 개체가 일반적으로 대리자이기 때문에 수행됩니다. MyClass가 델리게이트를 유지했다면 유지주기가있을 것입니다. MyClass 인스턴스가 있고 약한 백 포인터이기 때문에 대리자 참조를 지우는 대리자 인 클래스의 dealloc 메서드에서 좋은 생각입니다. 그렇지 않으면 MyClass 인스턴스를 유지하는 것이 있으면 매달린 포인터가 생깁니다.


+1 철저한 답변. Icing on the cake는 대리인에 대한보다 심층적 인 Apple 문서에 대한 링크가 될 것입니다. :-)
Quinn Taylor

Jon, 도와 주셔서 감사합니다. 도와 주셔서 정말 감사합니다. 미안하지만 대답이 너무 명확하지 않습니다. Message .m은 doSomething 함수 호출 중에 자신을 대리자로 설정하는 클래스입니다. doSomething은 사용자가 호출하는 콜백 함수입니까? 사용자가 doSomething을 호출하고 콜백 함수는 myClassWillDoSomethingg & myClassDidDoSomething이라는 인상을 받고 있기 때문입니다. 또한 콜백 함수를 호출하는 상위 클래스를 만드는 방법을 보여줄 수 있습니까? 저는 C 프로그래머이므로 아직 Obj-C 환경에 익숙하지 않습니다.
ReachConnection 2009-06-19

"Message .m"은 단지 .m 파일이라는 뜻입니다. 별도의 수업이있을 것입니다. "Foo"라고합시다. Foo는 "MyClass * myClass"변수를 가지며 어떤 시점에서 Foo는 "[myClass setDelegate : self]"라고 말할 것입니다. 그 후 어느 시점에서 foo를 포함한 누군가가 MyClass의 해당 인스턴스에서 doSomethingMethod를 호출하면 foo는 myClassWillDoSomething 및 myClassDidDoSomething 메서드가 호출됩니다. 실제로 대리자를 사용하지 않는 두 번째 다른 예제도 게시 할 것입니다.
Jon Hess

나는 .m이 "메시지"를 의미한다고 생각하지 않는다.
Chuck


140

완전성을 위해 StackOverflow RSS가 무작위로 질문을 부활 시켰으므로 다른 (최신) 옵션은 블록을 사용하는 것입니다.

@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);"에서 "^"문자는 무엇입니까? 평균? 그 라인이 무엇을하는지 설명해 주시겠습니까?
Konrad Höffner 2012

2
콜백 핸들러를 복사해야하는 이유에 대한 설명을 제공 할 수 있습니까?
Elliot Chance

52

다음은 델리게이트의 개념을 배제하고 원시 콜백을 수행하는 예입니다.

@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

일반적으로-[Foo doSomethingAndNotifyObject : withSelector :] 메서드는 비동기식이므로 여기보다 콜백이 더 유용합니다.


1
고마워요 존. 귀하의 의견 후 첫 번째 콜백 구현을 이해합니다. 또한 두 번째 콜백 구현이 더 간단합니다. 둘 다 아주 좋습니다.
ReachConnection 2009-06-22

1
이 Jon을 게시 해 주셔서 감사합니다. 매우 도움이되었습니다. [object performSelectorwithObject : self]를 변경해야했습니다. to [object performSelector : selector withObject : self]; 제대로 작동하도록합니다.
Banjer 2010 년

16

이 질문을 최신 상태로 유지하기 위해 iOS 5.0의 ARC 도입은 Blocks를 사용하여 더욱 간결하게 수행 할 수 있음을 의미합니다 .

@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의 블록 구문을 잊어 버린 경우 항상 F **** ng 블록 구문 이 있습니다.


@ 인터페이스에서해야 + (void)sayHi:(void(^)(NSString *reply))callback;하지+ (void)sayHi:(void(^)(NSString *))callback;
Tim007

앞서 언급 한 F **** ng 블록 구문에 따르지 않음 : - (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;(참고 parameterTypes하지 않음 parameters)
Ryan Brodie

4

콜백 : Objective C에는 4 가지 유형의 콜백이 있습니다.

  1. 선택기 유형 : NSTimer, UIPangesture가 Selector 콜백의 예입니다. 매우 제한된 코드 실행에 사용됩니다.

  2. 위임 유형 : 일반적이며 Apple 프레임 워크에서 가장 많이 사용됩니다. UITableViewDelegate, NSNURLConnectionDelegate. 일반적으로 서버에서 비동기식으로 많은 이미지 다운로드를 표시하는 데 사용됩니다.

  3. NSNotifications : NotificationCenter는 이벤트 발생시 많은 수취인에게 알림을 제공하는 Objective C의 기능 중 하나입니다.
  4. 블록 : 블록은 Objective C 프로그래밍에서 더 일반적으로 사용됩니다. 훌륭한 기능이며 코드 덩어리를 실행하는 데 사용됩니다. 이해하기 위해 튜토리얼을 참조 할 수도 있습니다. 블록 튜토리얼

다른 답변이 있으면 알려주십시오. 감사하겠습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.