ios - 如何在Objective-C里创建委托(delegates)?
天蓬老师
天蓬老师 2017-04-17 12:00:39
0
1
445

我知道委托如何工作,我也知道怎么使用。但是我该怎么创建呢?

原文:

How do I create delegates in Objective-C?

I know how delegates work, and I know how I can use them.
But how do I create them?

这是问题原文链接

天蓬老师
天蓬老师

欢迎选择我的课程,让我们一起见证您的进步~~

全部回覆(1)
小葫芦

1. 來自@Jesse Rusak 的回答:

Objective-C 委託就是已被指定為另一個委託的對象,沒有特殊的創建過程,你只要定義一個實現你感興趣的委託方法的類別就可以。 (雖然委託使用正式協議,但你必須得聲明委託來執行該協議,如下所示)
例如,假設你有個NSWindow。如果你想要實作他的委託的 windowDidMove: 方法,你可以建立一個這樣的類別:

@implementation MyClass
- (void)windowDidMove:(NSNotification*)notification { 
    // ... 
}
@end

然後建立一個MyClass的實例並制定為window的委託:

MyClass *myDelegate = [[MyClass alloc] init];
[window setDelegate: myDelegate];

在NSWindow方面, 可能有類似此的程式碼使用 respondsToSelector: 來看委託是否回應windowDidMove:訊息,如何合適就發送。

if([[self delegate] respondsToSelector:@selector(windowDidMove:)]) {
    [[self delegate] windowDidMove:notification];
}

委託資源本身是典型聲明的weak(ARC)或assign(預ARC)來避免循環,因為物件委託經常持有強引用該物件(例如,一個視圖控制器通常包含視圖委託)
要定義自己的委託,你需要在某個地方聲明方法。有兩個基本的方法,蘋果的文檔協議有討論過.

1) 一個非正式的協議

這個就跟NSWindow差不多,在NSObject的類別實作。例如,繼續上面的例子,這是從NSWindow.h:轉述的:

@interface NSObject(NSWindowNotifications)
- (void)windowDidMove:(NSNotification *)notification;
// ... 其他方法
@end

就像上面描述的那樣,當呼叫這個函數的時候,你會使用-respondsToSelector:,委託簡單的實作此方法,就完成了。這個方法在蘋果的庫裡是直接常見的,但是新的程式碼應該是用下面的更現代的方法。

2)一個正式的協議

新的選擇是聲明一個正式的協議。聲明應該像這個樣子:

@protocol NSWindowNotifications <NSObject>
@optional
- (void)windowDidMove:(NSNotification *)notification;
// ...其他方法
@end

這類似於一個藉口或抽象基底類,因為這為委託建立了一個特殊的類型,這種情況下是NSWindowNotifications。委託執行者應該採用這個協議:

@interface MyDelegate <NSWindowNotifications>
// ...
@end

然後再協定中執行方法。對於諸如@optional(就和大多數委託方法一樣)在協定中聲明的方法,你仍然需要在呼叫特殊方法之前檢查-respondsToSelector:。
蘋果建議這種方法,因為這個更精確,不會和NSObject弄混,並且提供更好的工具支援。

最佳化速度

取代檢查委託是否回應選擇器,你可以在設定委託時儲存相關資訊。使用bitfield是一個非常清楚的方法,如下:

@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 <JSSomethingDelegate>)aDelegate {
  if (delegate != aDelegate) {
    delegate = aDelegate;

    delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
    delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
  }
}
@end

然後,在正文裡,可以透過存取delegateRespondsTo來檢查委託處理郵件,而不是一遍又一遍的發送-respondsToSelector:。


2. 來自@Tibidabo

上面的方法很厲害!但如果你想在1分鐘內解決問題可以試試看這個:
MyClass.h檔案應該像這個樣子(用註解加上委託行)

#import <BlaClass/BlaClass.h>

@class MyClass;             //定义类,这样协议可以看到MyClass
@protocol MyClassDelegate   //定义委托协议
- (void) myClassDelegateMethod: (MyClass *) sender;  //定义在另一个类里实现的委托方法
@end //结束协议

@interface MyClass : NSObject {
}
@property (nonatomic, weak) id <MyClassDelegate> delegate; //定义 MyClassDelegate为委托

@end

MyClass.m 檔案應該像這樣:

#import "MyClass.h"
@implementation MyClass 
@synthesize delegate; //综合MyClassDelegate 委托

- (void) myMethodToDoStuff {
[self.delegate myClassDelegateMethod:self]; //这个会调用在其他类里实现的方法
}

@end

為了在其他的類別使用委託(本情況是UIViewController呼叫MyVC)MyVC.h:

#import "MyClass.h"
@interface MyVC:UIViewController <MyClassDelegate> { //make it a delegate for MyClassDelegate
}

MyVC.m:

myClass.delegate = self;          //设置委托至自身的某个地方

執行委託方法:

- (void) myClassDelegateMethod: (MyClass *) sender {
    NSLog(@"Delegates are great!");
}

3. 來自@umop

當用正式的協議方法創建委託支援時,我發現可以確保正確的類型檢查(雖然是運行時間,不是編譯時間),透過添加以下程式碼:

if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
    [NSException raise:@"MyDelegate Exception"
                format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}

在你的委託存取(setDelegate)程式碼,這個能將錯誤最小化。


4. 來自@Tom Andersen的回答

或許更多的是在於你所缺少的行。
如果從C++的角度來看,委託需要一點時間適應,但基本上「他們只是工作」。
委託實現的方式是:設定NSWindow的委託對象,但是對像只為一個或幾個可能的委託方法執行。所以會發生一些事,NSWindow想要調用對象,它只使用Objective-c的respondsToSelector方法來決定對像是否被調用,然後再調用。這就是objective-c的實作方式-根據需求尋找方法。
用你自己的對象實現這一點是非常瑣碎的,沒有什麼特別的事情,你甚至可以為讓一個實例有27個對象的NSArray,完全不同類型的對象,其中只有18個有-(void)setToBue;方法,其他的9個沒有。所以在18個需要完成的呼叫setToBlue,就像這樣:

for (id anObject in myArray)
{
  if ([anObject respondsToSelector:@selector(@"setToBlue")])
     [anObject setToBlue]; 
}

另外,委託是不保留的,所以需要在MyClass dealloc方法中將委託設定為nil。


5. 來自@RDC 的回答:

請看下面的教學是如何一步一步介紹iOS中的委託的。

  • iOS中的委託

我建立了兩個 ViewControllers (從一個傳送給另一個)
1. FirstViewController 執行委託(提供資料).
2. SecondViewController聲明委託(接收資料).

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板