대리인이 어떻게 작동하는지 알고 어떻게 사용할 수 있는지 알고 있습니다.
그러나 어떻게 만들 수 있습니까?
답변
Objective-C 대리자는 delegate
다른 개체 속성 에 할당 된 개체입니다. 하나를 만들려면 원하는 대리자 메서드를 구현하는 클래스를 정의하고 해당 클래스를 대리자 프로토콜을 구현하는 것으로 표시합니다.
예를 들어 UIWebView
. 대리자의 webViewDidStartLoad:
메서드 를 구현하려면 다음과 같은 클래스를 만들 수 있습니다.
@interface MyClass<UIWebViewDelegate>
// ...
@end
@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView {
// ...
}
@end
그런 다음 MyClass 인스턴스를 만들어 웹보기의 대리자로 할당 할 수 있습니다.
MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;
한편, UIWebView
대리자가 webViewDidStartLoad:
메시지를 사용 하여 메시지에 응답하고 respondsToSelector:
적절한 경우 메시지를 보내는 지 확인 하기 위해 이와 유사한 코드가 있을 수 있습니다.
if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
}
대리인 속성 자체는 일반적으로 weak
(ARC로) 선언 되거나assign
객체의 델리게이트는 종종 해당 객체에 대한 강력한 참조를 보유하기 때문에 루프 유지를 피하기 위해 ( (ARC 이전 됩니다. 예를 들어, 뷰 컨트롤러는 종종 뷰 컨트롤러에 포함 된 뷰의 위임자입니다.
반 대표단 만들기
자신의 델리게이트를 정의하려면 프로토콜 에 관한 Apple Docs에서 설명한대로 어딘가에 메소드를 선언해야 합니다 . 일반적으로 공식 프로토콜을 선언합니다. UIWebView.h에서 해석 된 선언은 다음과 같습니다.
@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end
이 UIWebViewDelegate
경우 델리게이트에 대한 특수 유형을 작성하므로 인터페이스 또는 추상 기본 클래스와 유사합니다 . 델리게이트 구현자는이 프로토콜을 채택해야합니다.
@interface MyClass <UIWebViewDelegate>
// ...
@end
그런 다음 프로토콜에서 메소드를 구현하십시오. 프로토콜에서 @optional
(대부분의 델리게이트 메소드와 같이) 선언 된 메소드의 -respondsToSelector:
경우 특정 메소드를 호출하기 전에 확인해야 합니다.
명명
위임 메소드는 일반적으로 위임 클래스 이름으로 시작하여 이름이 지정되며 위임 오브젝트를 첫 번째 매개 변수로 사용합니다. 그들은 종종 의지,해야 할 일 또는 행동을 사용합니다. 그래서 webViewDidStartLoad:
보다는 (첫 번째 매개 변수는 웹이다) loadStarted
(예를 들어, 매개 변수를 고려하지가).
속도 최적화
메시지를 보낼 때마다 대리자가 선택기에 응답하는지 확인하는 대신 대리자가 설정 될 때 해당 정보를 캐시 할 수 있습니다. 이를 수행하는 매우 깨끗한 방법 중 하나는 다음과 같이 비트 필드를 사용하는 것입니다.
@protocol SomethingDelegate <NSObject>
@optional
- (void)something:(id)something didFinishLoadingItem:(id)item;
- (void)something:(id)something didFailWithError:(NSError *)error;
@end
@interface Something : NSObject
@property (nonatomic, weak) id <SomethingDelegate> delegate;
@end
@implementation Something {
struct {
unsigned int didFinishLoadingItem:1;
unsigned int didFailWithError:1;
} delegateRespondsTo;
}
@synthesize delegate;
- (void)setDelegate:(id <SomethingDelegate>)aDelegate {
if (delegate != aDelegate) {
delegate = aDelegate;
delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
}
}
@end
그런 다음 본문에서 대리인이 반복 delegateRespondsTo
해서 보내지 않고 구조체 에 액세스하여 메시지를 처리하는지 확인할 수 있습니다 -respondsToSelector:
.
비공식 대의원
프로토콜이 존재하기 전에, 사용하는 것이 일반적이었다 카테고리 에를 NSObject
대리인이 구현할 수있는 방법을 선언 할 수 있습니다. 예를 들어 CALayer
여전히이 작업을 수행합니다.
@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end
이것은 컴파일러가 모든 객체가 구현할 수 있음을 알려줍니다 displayLayer:
.
그런 다음 -respondsToSelector:
위에서 설명한 것과 동일한 방법 을 사용 하여이 메소드를 호출합니다. 대리인은이 메서드를 구현하고 delegate
속성을 할당합니다. 그게 전부입니다 (프로토콜을 준수한다고 선언하지는 않음). 이 방법은 Apple의 라이브러리에서 일반적이지만 새 코드는 위의 최신 프로토콜 접근 방식을 사용해야합니다.이 접근 방식은 오염 NSObject
(자동 완성 기능의 유용성을 떨어 뜨림)하고 컴파일러가 오타 및 유사한 오류에 대해 경고하기 어렵 기 때문입니다.
답변
승인 된 답변은 훌륭하지만 1 분 답변을 찾고 있다면 다음을 시도하십시오.
MyClass.h 파일은 다음과 같아야합니다 (주석이있는 델리게이트 라인 추가!)
#import <BlaClass/BlaClass.h>
@class MyClass; //define class, so protocol can see MyClass
@protocol MyClassDelegate <NSObject> //define delegate protocol
- (void) myClassDelegateMethod: (MyClass *) sender; //define delegate method to be implemented within another class
@end //end protocol
@interface MyClass : NSObject {
}
@property (nonatomic, weak) id <MyClassDelegate> delegate; //define MyClassDelegate as delegate
@end
MyClass.m 파일은 다음과 같아야합니다
#import "MyClass.h"
@implementation MyClass
@synthesize delegate; //synthesise MyClassDelegate delegate
- (void) myMethodToDoStuff {
[self.delegate myClassDelegateMethod:self]; //this will call the method implemented in your other class
}
@end
다른 클래스 (이 경우 MyVC라고하는 UIViewController) MyVC.h에서 델리게이트를 사용하려면 :
#import "MyClass.h"
@interface MyVC:UIViewController <MyClassDelegate> { //make it a delegate for MyClassDelegate
}
MyVC.m :
myClass.delegate = self; //set its delegate to self somewhere
델리게이트 방법 구현
- (void) myClassDelegateMethod: (MyClass *) sender {
NSLog(@"Delegates are great!");
}
답변
델리게이트 지원을 만들기 위해 공식 프로토콜 방법을 사용할 때 다음과 같은 것을 추가하여 적절한 유형 검사 (컴파일 타임이 아닌 런타임)를 보장 할 수 있음을 발견했습니다.
if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
[NSException raise:@"MyDelegate Exception"
format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}
대리자 접근 자 (setDelegate) 코드에서. 이것은 실수를 최소화하는 데 도움이됩니다.
답변
부디! iOS에서 델리게이트가 어떻게 작동하는지 이해하려면 단계별 자습서를 아래에서 확인하십시오.
두 개의 ViewController를 만들었습니다 (데이터를 서로 보내기 위해)
- FirstViewController 구현 대리자 (데이터 제공).
- SecondViewController는 데이터를받을 델리게이트를 선언합니다.
답변
어쩌면 이것은 누락 된 내용에 더 가깝습니다.
C ++과 같은 관점에서 오면 대의원은 약간 익숙해 지지만 기본적으로 ‘그냥 작동합니다.
작동 방식은 NSWindow에 대리자로 작성한 일부 개체를 설정하지만 개체에는 가능한 많은 대리자 메서드 중 하나 또는 몇 가지에 대한 구현 (메서드) 만 있습니다. 그래서 어떤 일이 발생하고 NSWindow
객체를 호출하려고합니다-Objective-c를 사용합니다.respondsToSelector
메소드를 사용하여 객체가 해당 메소드를 호출할지 여부를 결정한 다음 호출합니다. 이것은 objective-c의 작동 방식입니다-요청시 방법을 찾아보십시오.
자신의 객체 로이 작업을 수행하는 것은 전적으로 사소한 일입니다. 특별히 진행되는 것은 없습니다. 예를 들어 NSArray
27 개의 객체, 모든 다른 종류의 객체, 18 개의 메소드 만 가질 수 있습니다 -(void)setToBue;
. 다른 9 개는 그렇지 않습니다. 따라서 setToBlue
다음과 같은 18 가지를 모두 호출 하십시오.
for (id anObject in myArray)
{
if ([anObject respondsToSelector:@selector(@"setToBlue")])
[anObject setToBlue];
}
델리게이트에 대한 또 다른 점은 유지되지 않는다는 것이므로 항상 메소드 nil
에서 델리게이트를로 설정 해야 MyClass dealloc
합니다.
답변
Apple에서 권장하는 모범 사례로서 대리인 (정의상 프로토콜 임)이 프로토콜을 따르는 것이 NSObject
좋습니다.
@protocol MyDelegate <NSObject>
...
@end
& 델리게이트 내에서 선택적 메소드 (즉, 반드시 구현할 필요는없는 메소드)를 작성하려면 다음 @optional
과 같이 주석을 사용할 수 있습니다 .
@protocol MyDelegate <NSObject>
...
...
// Declaration for Methods that 'must' be implemented'
...
...
@optional
...
// Declaration for Methods that 'need not necessarily' be implemented by the class conforming to your delegate
...
@end
따라서 선택적으로 지정한 메소드를 사용할 때 (클래스에서) respondsToSelector
뷰 (대리자에 맞는)가 실제로 선택적 메소드를 구현했는지 확인 해야합니다.
답변
대표단을 이해하면이 모든 답변이 의미가 있다고 생각합니다. 개인적으로 나는 C / C ++의 땅에서 왔으며 Fortran과 같은 절차 언어 이전에 C ++ 패러다임에서 비슷한 아날로그를 찾는 데 2 분이 걸렸습니다.
C ++ / Java 프로그래머에게 델리게이트를 설명한다면
대리인이란 무엇입니까? 다른 클래스 내의 클래스에 대한 정적 포인터입니다. 포인터를 할당하면 해당 클래스에서 함수 / 메소드를 호출 할 수 있습니다. 따라서 클래스의 일부 함수는 다른 클래스에 대한 “위임”됩니다 (C ++ 세계에서-클래스 객체 포인터로 가리키는 포인터).
프로토콜이란 무엇입니까? 개념적으로 대리자 클래스로 할당하는 클래스의 헤더 파일과 비슷한 용도로 사용됩니다. 프로토콜은 포인터가 클래스 내에서 대리자로 설정된 클래스에서 구현해야하는 메서드를 정의하는 명시적인 방법입니다.
C ++에서 비슷한 것을 어떻게 할 수 있습니까? C ++ 에서이 작업을 수행하려고하면 클래스 정의에서 클래스 (객체)에 대한 포인터를 정의한 다음 기본 클래스에 대한 위임으로 추가 기능을 제공하는 다른 클래스에 연결합니다. 그러나이 배선은 코드 내에서 유지되어야하며 서투르고 오류가 발생하기 쉽습니다. 목표 C는 프로그래머가이 규범을 유지하는 데 최선이 아니라고 가정하고 깨끗한 구현을 시행하기 위해 컴파일러 제한을 제공합니다.