Objective-C에서 델리게이트를 어떻게 생성합니까?
대의원이 어떻게 작동하는지, 어떻게 사용할 수 있는지 알고 있습니다.
하지만 어떻게 만드나요?
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) 코드에서. 이는 실수를 최소화하는 데 도움이됩니다.
아마도 이것은 당신이 놓친 라인에 더 가깝습니다.
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
것입니다.
부디! iOS에서 대리인이 어떻게 작동하는지 이해하려면 아래의 간단한 단계별 자습서를 확인하십시오.
두 개의 ViewController를 만들었습니다 (데이터를 다른 곳으로 보내기 위해)
- FirstViewController는 델리게이트 (데이터 제공)를 구현합니다.
- SecondViewController는 (데이터를받을) 델리게이트를 선언합니다.
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 ++에서이 작업을 수행하려는 경우 클래스 정의에서 클래스 (객체)에 대한 포인터를 정의한 다음 기본 클래스에 대한 대리자로 추가 함수를 제공 할 다른 클래스에 연결합니다. 그러나이 배선은 코드 내에서 관리되어야하며 서투르고 오류가 발생하기 쉽습니다. Objective C는 프로그래머가이 규정을 유지하는 데 최선이 아니라고 가정하고 깔끔한 구현을 시행하기 위해 컴파일러 제한을 제공합니다.
Swift 버전
델리게이트는 다른 클래스에 대해 일부 작업을 수행하는 클래스입니다. Swift에서 이것이 어떻게 수행되는지를 보여주는 다소 어리석은 (하지만 깨달음을 바라는) 플레이 그라운드 예제를 보려면 다음 코드를 읽으십시오.
// A protocol is just a list of methods (and/or properties) that must
// be used by any class that adopts the protocol.
protocol OlderSiblingDelegate: class {
// This protocol only defines one required method
func getYourNiceOlderSiblingAGlassOfWater() -> String
}
class BossyBigBrother {
// The delegate is the BossyBigBrother's slave. This position can
// be assigned later to whoever is available (and conforms to the
// protocol).
weak var delegate: OlderSiblingDelegate?
func tellSomebodyToGetMeSomeWater() -> String? {
// The delegate is optional because there might not be anyone
// nearby to boss around.
return delegate?.getYourNiceOlderSiblingAGlassOfWater()
}
}
// PoorLittleSister conforms to the OlderSiblingDelegate protocol
class PoorLittleSister: OlderSiblingDelegate {
// This method is repquired by the protocol, but the protocol said
// nothing about how it needs to be implemented.
func getYourNiceOlderSiblingAGlassOfWater() -> String {
return "Go get it yourself!"
}
}
// initialize the classes
let bigBro = BossyBigBrother()
let lilSis = PoorLittleSister()
// Set the delegate
// bigBro could boss around anyone who conforms to the
// OlderSiblingDelegate protocol, but since lilSis is here,
// she is the unlucky choice.
bigBro.delegate = lilSis
// Because the delegate is set, there is a class to do bigBro's work for him.
// bigBro tells lilSis to get him some water.
if let replyFromLilSis = bigBro.tellSomebodyToGetMeSomeWater() {
print(replyFromLilSis) // "Go get it yourself!"
}
실제로 대리자는 다음과 같은 상황에서 자주 사용됩니다.
- 수업이 다른 수업에 정보를 전달해야 할 때
- 클래스가 다른 클래스가 사용자 정의 할 수 있도록 허용하려는 경우
클래스는 위임 클래스가 필수 프로토콜을 준수한다는 점을 제외하고는 서로에 대해 미리 알 필요가 없습니다.
다음 두 기사를 읽는 것이 좋습니다. 그들은 문서 보다 훨씬 더 잘 대리인을 이해하도록 도와주었습니다 .
좋아, 이것은 실제로 질문에 대한 답은 아니지만 자신의 대리인을 만드는 방법을 찾고 있다면 훨씬 더 간단한 것이 더 나은 대답이 될 수 있습니다.
나는 거의 필요하지 않기 때문에 대리인을 거의 구현하지 않습니다. 대리자 개체에 대리자를 하나만 가질 수 있습니다. 따라서 대리인이 단방향 통신 / 데이터 전달을 원하는 경우 알림보다 훨씬 낫습니다.
NSNotification은 둘 이상의 수신자에게 객체를 전달할 수 있으며 사용이 매우 쉽습니다. 다음과 같이 작동합니다.
MyClass.m 파일은 다음과 같아야합니다.
#import "MyClass.h"
@implementation MyClass
- (void) myMethodToDoStuff {
//this will post a notification with myClassData (NSArray in this case) in its userInfo dict and self as an object
[[NSNotificationCenter defaultCenter] postNotificationName:@"myClassUpdatedData"
object:self
userInfo:[NSDictionary dictionaryWithObject:selectedLocation[@"myClassData"] forKey:@"myClassData"]];
}
@end
다른 클래스에서 알림을 사용하려면 : 관찰자로 클래스를 추가합니다.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherClassUpdatedItsData:) name:@"myClassUpdatedData" object:nil];
선택기를 구현합니다.
- (void) otherClassUpdatedItsData:(NSNotification *)note {
NSLog(@"*** Other class updated its data ***");
MyClass *otherClass = [note object]; //the object itself, you can call back any selector if you want
NSArray *otherClassData = [note userInfo][@"myClassData"]; //get myClass data object and do whatever you want with it
}
다음과 같은 경우 관찰자로서 클래스를 제거하는 것을 잊지 마십시오.
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
여러분이 개발 한 클래스가 있고 어떤 이벤트가 발생했을 때이를 알릴 수 있도록 델리게이트 속성을 선언하고 싶다고 가정 해 보겠습니다.
@class myClass;
@protocol myClassDelegate <NSObject>
-(void)myClass:(MyClass*)myObject requiredEventHandlerWithParameter:(ParamType*)param;
@optional
-(void)myClass:(MyClass*)myObject optionalEventHandlerWithParameter:(ParamType*)param;
@end
@interface MyClass : NSObject
@property(nonatomic,weak)id< MyClassDelegate> delegate;
@end
따라서 MyClass
헤더 파일 (또는 별도의 헤더 파일) 에서 프로토콜을 선언하고 위임이 구현해야하는 필수 / 선택적 이벤트 핸들러를 선언 한 다음 MyClass
( id< MyClassDelegate>
) 형식 의 속성을 선언합니다. 이는 다음 을 준수하는 모든 목적 c 클래스를 의미합니다. 프로토콜 MyClassDelegate
을 사용하면 delegate 속성이 weak로 선언되어 있음을 알 수 있습니다. 이것은 유지주기를 방지하는 데 매우 중요합니다 (대리자가 MyClass
인스턴스를 유지하는 경우가 많으므로 대리인을 유지로 선언하면 둘 다 서로 유지되고 둘 다 유지되지 않습니다). 그들 중 공개 될 것입니다).
또한 프로토콜 메서드가 MyClass
인스턴스를 매개 변수로 대리자에게 전달한다는 것을 알 수 있습니다 . 대리자 가 인스턴스에서 일부 메서드를 호출하려는 경우에 가장 좋은 방법이며 대리자 가 여러 인스턴스에 대해 MyClass
자신을 선언 할 때도 도움이됩니다. 당신의 인스턴스 와 그들 모두에게 자신을 선언 합니다.MyClassDelegate
MyClass
UITableView's
ViewController
UITableViewDelegate
내부 MyClass
에서 다음과 같이 선언 된 이벤트로 대리자에게 알립니다.
if([_delegate respondsToSelector:@selector(myClass: requiredEventHandlerWithParameter:)])
{
[_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}
델리게이트가이를 구현하지 않고 앱이 충돌 할 경우 (프로토콜 메서드가 필요한 경우에도) 호출하려는 프로토콜 메서드에 델리게이트가 응답하는지 먼저 확인합니다.
다음은 대리자를 만드는 간단한 방법입니다.
.h 파일에 프로토콜을 만듭니다. @class 다음에 UIViewController의 이름을 사용하여 프로토콜 앞에 정의되어 있는지 확인하십시오.< As the protocol I am going to use is UIViewController class>.
1 단계 : UIViewController 클래스의 하위 클래스가 될 "YourViewController"라는 새 클래스 프로토콜을 만들고이 클래스를 두 번째 ViewController에 할당합니다.
2 단계 : "YourViewController"파일로 이동하여 다음과 같이 수정합니다.
#import <UIKit/UIkit.h>
@class YourViewController;
@protocol YourViewController Delegate <NSObject>
@optional
-(void)defineDelegateMethodName: (YourViewController *) controller;
@required
-(BOOL)delegateMethodReturningBool: (YourViewController *) controller;
@end
@interface YourViewController : UIViewController
//Since the property for the protocol could be of any class, then it will be marked as a type of id.
@property (nonatomic, weak) id< YourViewController Delegate> delegate;
@end
프로토콜 동작에 정의 된 메서드는 프로토콜 정의의 일부로 @optional 및 @required를 사용하여 제어 할 수 있습니다.
단계 : 3 : 델리게이트 구현
#import "delegate.h"
@interface YourDelegateUser ()
<YourViewControllerDelegate>
@end
@implementation YourDelegateUser
- (void) variousFoo {
YourViewController *controller = [[YourViewController alloc] init];
controller.delegate = self;
}
-(void)defineDelegateMethodName: (YourViewController *) controller {
// handle the delegate being called here
}
-(BOOL)delegateMethodReturningBool: (YourViewController *) controller {
// handle the delegate being called here
return YES;
}
@end
// 호출하기 전에 메서드가 정의되었는지 테스트
- (void) someMethodToCallDelegate {
if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
[self.delegate delegateMethodName:self];
}
}
고유 한 대리자를 만들려면 먼저 구현하지 않고 프로토콜을 만들고 필요한 메서드를 선언해야합니다. 그런 다음 대리자 또는 대리자 메서드를 구현하려는 헤더 클래스에이 프로토콜을 구현합니다.
프로토콜은 아래와 같이 선언해야합니다.
@protocol ServiceResponceDelegate <NSObject>
- (void) serviceDidFailWithRequestType:(NSString*)error;
- (void) serviceDidFinishedSucessfully:(NSString*)success;
@end
이것은 일부 작업이 수행되어야하는 서비스 클래스입니다. 대리자를 정의하는 방법과 대리자를 설정하는 방법을 보여줍니다. 작업이 완료된 후 구현 클래스에서 대리자의 메서드가 호출됩니다.
@interface ServiceClass : NSObject
{
id <ServiceResponceDelegate> _delegate;
}
- (void) setDelegate:(id)delegate;
- (void) someTask;
@end
@implementation ServiceClass
- (void) setDelegate:(id)delegate
{
_delegate = delegate;
}
- (void) someTask
{
/*
perform task
*/
if (!success)
{
[_delegate serviceDidFailWithRequestType:@”task failed”];
}
else
{
[_delegate serviceDidFinishedSucessfully:@”task success”];
}
}
@end
델리게이트를 자신으로 설정하여 서비스 클래스가 호출되는 기본 뷰 클래스입니다. 또한 프로토콜은 헤더 클래스에서 구현됩니다.
@interface viewController: UIViewController <ServiceResponceDelegate>
{
ServiceClass* _service;
}
- (void) go;
@end
@implementation viewController
//
//some methods
//
- (void) go
{
_service = [[ServiceClass alloc] init];
[_service setDelegate:self];
[_service someTask];
}
그게 다입니다.이 클래스에서 델리게이트 메서드를 구현하면 작업 / 작업이 완료되면 제어가 다시 돌아옵니다.
면책 조항 :이은이다 Swift
을 만드는 방법의 버전 delegate
.
그렇다면 대의원이란 무엇입니까? … 소프트웨어 개발에는 주어진 컨텍스트 내에서 일반적으로 발생하는 문제를 해결하는 데 도움이되는 일반적인 재사용 가능한 솔루션 아키텍처가 있습니다. 이러한 "템플릿"은 말하자면 디자인 패턴으로 가장 잘 알려져 있습니다. 델리게이트는 특정 이벤트가 발생할 때 한 개체가 다른 개체에 메시지를 보낼 수 있도록하는 디자인 패턴입니다. 객체 A가 객체 B를 호출하여 작업을 수행한다고 상상해보십시오. 작업이 완료되면 객체 A는 B가 작업을 완료했음을 알고 필요한 조치를 취해야합니다. 대의원의 도움을 받아 수행 할 수 있습니다!
더 나은 설명을 위해 간단한 응용 프로그램에서 Swift를 사용하여 클래스간에 데이터를 전달하는 사용자 지정 대리자를 만드는 방법을 보여 드리겠습니다. 시작 프로젝트를 다운로드하거나 복제하여 실행하십시오!
두 클래스와 응용 프로그램을 참조 할 수 ViewController A
및 ViewController B
. B에는 탭에서의 배경색을 변경하는 두 가지보기가 있습니다. ViewController
너무 복잡하지 않습니까? 이제 클래스 B의 뷰를 탭할 때 클래스 A의 배경색도 쉽게 변경할 수있는 방법을 생각해 봅시다.
문제는이 뷰가 클래스 B의 일부이고 클래스 A에 대해 전혀 모른다는 것이므로이 두 클래스간에 통신 할 방법을 찾아야합니다. 여기서 위임이 빛을 발합니다. 구현을 6 단계로 나누어 필요할 때 치트 시트로 사용할 수 있습니다.
1 단계 : ClassBVC 파일에서 pragma mark 1 단계를 찾아 추가합니다.
//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}
첫 번째 단계는를 생성하는 것 protocol
입니다.이 경우 클래스 B에서 프로토콜을 생성합니다. 프로토콜 내에서 구현 요구 사항에 따라 원하는만큼의 함수를 생성 할 수 있습니다. 이 경우 옵션 UIColor
을 인수로 받아들이는 간단한 함수 하나만 있습니다. delegate
클래스 이름 끝에 단어 를 추가하여 프로토콜 이름을 지정하는 것이 좋습니다 ( 이 경우 ClassBVCDelegate
.
2 단계 : 2 단계에서 pragma 표시를 ClassVBC
찾아 추가합니다.
//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?
여기서는 클래스에 대한 델리게이트 속성을 생성하고이 속성은 protocol
유형을 채택 해야하며 선택 사항이어야합니다. 또한 유지주기와 잠재적 인 메모리 누수를 방지하기 위해 속성 앞에 weak 키워드를 추가해야합니다. 이것이 의미하는 바를 지금은 걱정하지 마십시오.이 키워드를 추가하는 것을 잊지 마십시오.
3 단계 : handleTap 내부 프라 그마 마크 3 단계를 찾을 method
에서 ClassBVC
이 추가
//MARK: step 3 Add the delegate method call here.
delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)
알아야 할 한 가지는 앱을 실행하고 아무 뷰나 탭하면 새로운 동작이 표시되지 않으며 맞습니다.하지만 제가 지적하고 싶은 점은 델리게이트가 호출 될 때 앱이 충돌하지 않는다는 것입니다. 그것은 우리가 그것을 선택적인 값으로 생성하기 때문이며 그것이 위임자가 아직 존재하지 않아도 충돌하지 않는 이유입니다. 이제 ClassAVC
파일 로 이동 하여 위임자를 만드십시오.
4 단계 : handleTap 메서드 내부에서 pragma 표시 4 단계를 찾아서 ClassAVC
이와 같이 클래스 유형 옆에 추가합니다.
//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}
이제 ClassAVC가 ClassBVCDelegate
프로토콜을 채택 했으므로 컴파일러에서 " 'ClassAVC 유형이'ClassBVCDelegate '프로토콜을 준수하지 않습니다. 이는 프로토콜의 메서드를 아직 사용하지 않았 음을 의미 할뿐입니다."라는 오류가 발생하는 것을 볼 수 있습니다. 클래스 A가 프로토콜을 채택하면 클래스 B와 계약을 체결하는 것과 같습니다.이 계약은 "나를 채택하는 모든 클래스는 내 기능을 사용해야합니다!"라고 말합니다.
참고 : Objective-C
배경 에서 온 경우 해당 방법을 선택 사항으로 만드는 오류를 종료 할 수도 있다고 생각할 수 있지만 놀랍게도 Swift
언어는 선택 사항을 지원하지 않습니다. protocols
원하는 경우 만들 수 있습니다. 당신의 확장 protocol
또는 protocol
구현 에서 @objc 키워드를 사용하십시오 .
개인적으로, 다른 선택적인 방법으로 프로토콜을 만들어야한다면 다른 방법으로 나누는 것을 선호합니다. 그렇게하면 protocols
객체에 하나의 책임을 부여한다는 개념을 따를 것이지만 특정 구현에 따라 다를 수 있습니다.
여기 에 선택적 방법에 대한 좋은 기사가 있습니다.
5 단계 : segue 준비 메서드에서 pragma 마크 5 단계를 찾아 추가합니다.
//MARK: step 5 create a reference of Class B and bind them through the `prepareforsegue` method.
if let nav = segue.destination as? UINavigationController, let classBVC = nav.topViewController as? ClassBVC {
classBVC.delegate = self
}
여기서 우리는 단지 인스턴스를 생성하고 ClassBVC
그 델리게이트를 self에게 할당하는 것입니다.하지만 여기서 self는 무엇입니까? 자아는 ClassAVC
위임받은 자입니다!
6 단계 : 마지막으로에서 pragma 6 단계를 찾아 ClassAVC
의 함수를 사용하고 protocol
func changeBackgroundColor 입력을 시작 하면 자동 완성되는 것을 확인할 수 있습니다. 내부에 구현을 추가 할 수 있습니다.이 예제에서는 배경색 만 변경하고 추가합니다.
//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}
이제 앱을 실행하세요!
Delegates
예고없이 사용할 수 있습니다 tableview
. 과거에 위임을 사용하여 여러 클래스의 UIKIT
작업 을 만들면 frameworks
이러한 주요 문제를 해결할 수 있습니다.
- 물체를 단단히 결합하지 마십시오.
- 객체를 하위 클래스로 만들 필요없이 동작과 모양을 수정합니다.
- 임의의 개체에 대해 작업을 처리 할 수 있습니다.
축하합니다. 사용자 지정 델리게이트를 구현했습니다. 아마 생각하고 계시다는 것을 알고 있습니다. 이것 때문에 많은 문제가 있습니까? 글쎄요, 위임은 iOS
개발자 가되고 싶다면 이해해야 할 매우 중요한 디자인 패턴 이며 항상 객체간에 일대일 관계가 있음을 명심하십시오.
여기 에서 원본 튜토리얼을 볼 수 있습니다.
답변은 실제로 답이되지만 델리게이트 생성을위한 "치트 시트"를 제공하고 싶습니다.
DELEGATE SCRIPT
CLASS A - Where delegate is calling function
@protocol <#Protocol Name#> <NSObject>
-(void)delegateMethod;
@end
@interface <#Some ViewController#> : <#UIViewController#>
@property (nonatomic, assign) id <<#Protocol Name#>> delegate;
@end
@implementation <#Some ViewController#>
-(void)someMethod {
[self.delegate methodName];
}
@end
CLASS B - Where delegate is called
@interface <#Other ViewController#> (<#Delegate Name#>) {}
@end
@implementation <#Other ViewController#>
-(void)otherMethod {
CLASSA *classA = [[CLASSA alloc] init];
[classA setDelegate:self];
}
-delegateMethod() {
}
@end
ViewController.h
@protocol NameDelegate <NSObject>
-(void)delegateMEthod: (ArgType) arg;
@end
@property id <NameDelegate> delegate;
ViewController.m
[self.delegate delegateMEthod: argument];
MainViewController.m
ViewController viewController = [ViewController new];
viewController.delegate = self;
방법:
-(void)delegateMEthod: (ArgType) arg{
}
내 관점에서 해당 대리자 메서드에 대해 별도의 클래스를 만들고 원하는 곳에서 사용할 수 있습니다.
내 사용자 정의 DropDownClass.h에서
typedef enum
{
DDSTATE,
DDCITY
}DropDownType;
@protocol DropDownListDelegate <NSObject>
@required
- (void)dropDownDidSelectItemWithString:(NSString*)itemString DropDownType:(DropDownType)dropDownType;
@end
@interface DropDownViewController : UIViewController
{
BOOL isFiltered;
}
@property (nonatomic, assign) DropDownType dropDownType;
@property (weak) id <DropDownListDelegate> delegate;
@property (strong, nonatomic) NSMutableArray *array1DropDown;
@property (strong, nonatomic) NSMutableArray *array2DropDown;
그 후 in.m 파일은 객체로 배열을 생성합니다.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat rowHeight = 44.0f;
return rowHeight;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return isFiltered?[self.array1DropDown count]:[self.array2DropDown count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"TableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (self.delegate) {
if (self.dropDownType == DDCITY) {
cell.textLabel.text = [self.array1DropDown objectAtIndex:indexPath.row];
}
else if (self.dropDownType == DDSTATE) {
cell.textLabel.text = [self.array2DropDown objectAtIndex:indexPath.row];
}
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self dismissViewControllerAnimated:YES completion:^{
if(self.delegate){
if(self.dropDownType == DDCITY){
[self.delegate dropDownDidSelectItemWithString:[self.array1DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
}
else if (self.dropDownType == DDSTATE) {
[self.delegate dropDownDidSelectItemWithString:[self.array2DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
}
}
}];
}
여기에서 모두 사용자 지정 대리자 클래스에 대해 설정 한 후 원하는 위치에이 대리자 메서드를 사용할 수 있습니다.
그 후 내 다른 viewcontroller 가져 오기에서
이와 같은 대리자 메서드를 호출하는 작업을 만듭니다.
- (IBAction)dropDownBtn1Action:(id)sender {
DropDownViewController *vehicleModelDropView = [[DropDownViewController alloc]init];
vehicleModelDropView.dropDownType = DDCITY;
vehicleModelDropView.delegate = self;
[self presentViewController:vehicleModelDropView animated:YES completion:nil];
}
다음과 같은 대리자 메서드 호출 후
- (void)dropDownDidSelectItemWithString:(NSString *)itemString DropDownType:(DropDownType)dropDownType {
switch (dropDownType) {
case DDCITY:{
if(itemString.length > 0){
//Here i am printing the selected row
[self.dropDownBtn1 setTitle:itemString forState:UIControlStateNormal];
}
}
break;
case DDSTATE: {
//Here i am printing the selected row
[self.dropDownBtn2 setTitle:itemString forState:UIControlStateNormal];
}
default:
break;
}
}
위임 :-만들기
@protocol addToCartDelegate <NSObject>
-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;
@end
전송하고 데이터를 보내는 데 대리인을 지정하십시오.
[self.delegate addToCartAction:itemsModel isAdded:YES];
//1.
//Custom delegate
@protocol TB_RemovedUserCellTag <NSObject>
-(void)didRemoveCellWithTag:(NSInteger)tag;
@end
//2.
//Create a weak reference in a class where you declared the delegate
@property(weak,nonatomic)id <TB_RemovedUserCellTag> removedCellTagDelegate;
//3.
// use it in the class
[self.removedCellTagDelegate didRemoveCellWithTag:self.tag];
//4. import the header file in the class where you want to conform to the protocol
@interface MyClassUsesDelegate ()<TB_RemovedUserCellTag>
@end
// 5. 클래스 .m-(void) didRemoveCellWithTag : (NSInteger) tag {NSLog @ ( "Tag % d", tag);
}
예를 들어 온라인으로 제품을 구매하면 배송 / 배송 등의 과정을 거쳐서 각기 다른 팀에서 처리하므로 배송이 완료되면 배송팀에서 배송팀에 알려야하며이 정보를 브로드 캐스팅하면서 일대일 커뮤니케이션이어야합니다. 다른 사람에게 오버 헤드가 될 수 있습니다 / 공급 업체는이 정보를 필요한 사람에게만 전달하려고 할 수 있습니다.
따라서 앱 측면에서 생각하면 이벤트는 온라인 주문이 될 수 있고 다른 팀은 여러 뷰와 같을 수 있습니다.
다음은 ShippingView를 배송 팀으로, DeliveryView를 배송 팀으로 고려하는 코드입니다.
//Declare the protocol with functions having info which needs to be communicated
protocol ShippingDelegate : class {
func productShipped(productID : String)
}
//shippingView which shows shipping status of products
class ShippingView : UIView
{
weak var delegate:ShippingDelegate?
var productID : String
@IBAction func checkShippingStatus(sender: UIButton)
{
// if product is shipped
delegate?.productShipped(productID: productID)
}
}
//Delivery view which shows delivery status & tracking info
class DeliveryView: UIView,ShippingDelegate
{
func productShipped(productID : String)
{
// update status on view & perform delivery
}
}
//Main page on app which has both views & shows updated info on product whole status
class ProductViewController : UIViewController
{
var shippingView : ShippingView
var deliveryView : DeliveryView
override func viewDidLoad() {
super.viewDidLoad()
// as we want to update shipping info on delivery view, so assign delegate to delivery object
// whenever shipping status gets updated it will call productShipped method in DeliveryView & update UI.
shippingView.delegate = deliveryView
//
}
}
참고 URL : https://stackoverflow.com/questions/626898/how-do-i-create-delegates-in-objective-c
'Nice programing' 카테고리의 다른 글
C #에서 명령 줄 인수를 구문 분석하는 가장 좋은 방법은 무엇입니까? (0) | 2020.09.29 |
---|---|
String.slice와 String.substring의 차이점은 무엇입니까? (0) | 2020.09.29 |
pg gem을 설치하려고 할 때 'libpq-fe.h 헤더를 찾을 수 없습니다. (0) | 2020.09.29 |
TINYTEXT, TEXT, MEDIUMTEXT 및 LONGTEXT 최대 저장 크기 (0) | 2020.09.29 |
C ++ 11에서 T && (이중 앰퍼샌드)는 무엇을 의미합니까? (0) | 2020.09.29 |