Bagaimana cara membuat delegasi di Objective-C?

Jawaban:

889

Delegasi Objective-C adalah objek yang telah ditugaskan ke delegateproperti objek lain. Untuk membuatnya, Anda mendefinisikan kelas yang mengimplementasikan metode delegasi yang Anda minati, dan menandai kelas itu sebagai mengimplementasikan protokol delegasi.

Misalnya, anggap Anda memiliki UIWebView. Jika Anda ingin menerapkan webViewDidStartLoad:metode pendelegasiannya , Anda dapat membuat kelas seperti ini:

@interface MyClass<UIWebViewDelegate>
// ...
@end

@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView { 
    // ... 
}
@end

Kemudian Anda bisa membuat instance dari MyClass dan menetapkannya sebagai delegasi tampilan web:

MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;

Di UIWebViewsamping itu, mungkin memiliki kode yang mirip dengan ini untuk melihat apakah delegasi menanggapi webViewDidStartLoad:pesan menggunakan respondsToSelector:dan mengirimkannya jika perlu.

if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
    [self.delegate webViewDidStartLoad:self];
}

Properti delegate itu sendiri biasanya dinyatakan weak(dalam ARC) atau assign(pra-ARC) untuk menghindari loop mempertahankan, karena delegasi suatu objek sering memegang referensi yang kuat untuk objek itu. (Misalnya, pengontrol tampilan seringkali merupakan delegasi dari tampilan yang dikandungnya.)

Membuat Delegasi untuk Kelas Anda

Untuk menentukan delegasi Anda sendiri, Anda harus mendeklarasikan metode mereka di suatu tempat, seperti yang dibahas dalam Apple Documents tentang protokol . Anda biasanya mendeklarasikan protokol formal. Deklarasi, diparafrasekan dari UIWebView.h, akan terlihat seperti ini:

@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end

Ini analog dengan antarmuka atau kelas dasar abstrak, karena ini membuat jenis khusus untuk delegasi Anda, UIWebViewDelegatedalam hal ini. Delegasi pelaksana harus mengadopsi protokol ini:

@interface MyClass <UIWebViewDelegate>
// ...
@end

Dan kemudian mengimplementasikan metode dalam protokol. Untuk metode yang dinyatakan dalam protokol sebagai @optional(seperti kebanyakan metode delegasi), Anda perlu memeriksa -respondsToSelector:sebelum memanggil metode tertentu di dalamnya.

Penamaan

Metode delegasi biasanya dinamai dimulai dengan nama kelas pendelegasian, dan mengambil objek pendelegasian sebagai parameter pertama. Mereka juga sering menggunakan kemauan, harus-, atau melakukan. Jadi, webViewDidStartLoad:(parameter pertama adalah tampilan web) daripada loadStarted(tanpa parameter) misalnya.

Optimasi Kecepatan

Alih-alih memeriksa apakah seorang delegasi merespons pemilih setiap kali kami ingin mengirimkannya, Anda dapat menyimpan informasi tersebut ketika delegasi ditetapkan. Salah satu cara yang sangat bersih untuk melakukan ini adalah dengan menggunakan bitfield, sebagai berikut:

@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

Kemudian, di dalam tubuh, kita dapat memeriksa bahwa delegasi kita menangani pesan dengan mengakses delegateRespondsTostruct kita , daripada dengan mengirim -respondsToSelector:berulang-ulang.

Delegasi Informal

Sebelum protokol ada, itu adalah umum untuk menggunakan kategori pada NSObjectuntuk menyatakan metode delegasi bisa melaksanakan. Misalnya, CALayermasih melakukan ini:

@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end

Ini memberitahu kompiler bahwa objek apa pun mungkin menerapkan displayLayer:.

Anda kemudian akan menggunakan -respondsToSelector:pendekatan yang sama seperti yang dijelaskan di atas untuk memanggil metode ini. Delegasi mengimplementasikan metode ini dan menetapkan delegateproperti, dan hanya itu (tidak ada yang menyatakan Anda mematuhi protokol). Metode ini umum di perpustakaan Apple, tetapi kode baru harus menggunakan pendekatan protokol yang lebih modern di atas, karena pendekatan ini mencemari NSObject(yang membuat autocomplete kurang berguna) dan menyulitkan kompiler untuk memperingatkan Anda tentang kesalahan ketik dan kesalahan serupa.

Jesse Rusak
sumber
Saya pikir Anda perlu memberikan unsigned inttipe BOOLsebagai nilai pengembalian delegate respondsToSelectortipe BOOL.
Roland
Bisakah mendelegasikan digunakan untuk Polimorfisme seperti di C ++?
@Dan Ya, tentu. Protokol secara umum digunakan untuk polimorfisme.
Jesse Rusak
@JesseRusak Saya pikir "JSSomethingDelegate" harus menjadi "SomethingDelegate" untuk konsistensi :)
Hans Knöchel
382

Jawaban yang disetujui bagus, tetapi jika Anda mencari jawaban 1 menit coba ini:

File MyClass.h akan terlihat seperti ini (tambahkan baris delegasi dengan komentar!)

#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

File MyClass.m akan terlihat seperti ini

#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

Untuk menggunakan delegasi Anda di kelas lain (UIViewController disebut MyVC dalam kasus ini) 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

Terapkan metode delegasi

- (void) myClassDelegateMethod: (MyClass *) sender {
    NSLog(@"Delegates are great!");
}
Tibidabo
sumber
4
Sangat bagus menggunakan jawaban ini sebagai referensi cepat. Tapi mengapa properti delegasi di MyClass.h Anda ditandai sebagai 'IBOutlet'?
Arno van der Meer
4
@ArnovanderMeer Tangkapan yang bagus! Saya tidak ingat mengapa. Saya membutuhkannya dalam proyek saya tetapi tidak dalam contoh ini, saya menghapusnya. thx
Tibidabo
Terima kasih. Sebagus dan selengkap jawaban yang diterima, saya belajar terbaik dari beberapa kode sampel yang ringkas. Ada baiknya memiliki dua jawaban.
sudo
@ Tibibabo Benar-benar luar biasa. Saya benar-benar berharap semua orang bisa menjelaskan konsep pemrograman seperti ini. Saya telah melihat ratusan penjelasan, tentang 'delegasi', selama bertahun-tahun dan tidak pernah benar-benar memahami teori ini sampai sekarang! Terima kasih banyak ...
Charles Robertson
5
Di mana myClassinstantiated di dalam MyVC.m?
Lane Rettig
18

Saat menggunakan metode protokol formal untuk membuat dukungan delegasi, saya telah menemukan bahwa Anda dapat memastikan pemeriksaan tipe yang tepat (meskipun, runtime, bukan waktu kompilasi) dengan menambahkan sesuatu seperti:

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

dalam kode pengakses delegasi Anda (setDelegate). Ini membantu meminimalkan kesalahan.

umop
sumber
18

Silahkan! periksa tutorial langkah demi langkah di bawah ini untuk memahami cara kerja Delegasi di iOS.

Delegasikan di iOS

Saya telah membuat dua ViewControllers (untuk mengirim data dari satu ke yang lain)

  1. Delegasi implement FirstViewController (yang menyediakan data).
  2. SecondViewController menyatakan delegasi (yang akan menerima data).
swiftBoy
sumber
17

Mungkin ini lebih sesuai dengan apa yang Anda lewatkan:

Jika Anda datang dari sudut pandang C ++ seperti, delegasi mengambil sedikit membiasakan diri - tetapi pada dasarnya 'mereka hanya bekerja'.

Cara kerjanya adalah bahwa Anda menetapkan beberapa objek yang Anda tulis sebagai delegasi ke NSWindow, tetapi objek Anda hanya memiliki implementasi (metode) untuk satu atau beberapa dari banyak metode delegasi yang mungkin. Jadi sesuatu terjadi, dan NSWindowingin memanggil objek Anda - ia hanya menggunakan respondsToSelectormetode Objective-c untuk menentukan apakah objek Anda ingin metode itu dipanggil, dan kemudian menyebutnya. Beginilah cara obyektif-c bekerja - metode dicari sesuai permintaan.

Sangat sepele untuk melakukan ini dengan objek Anda sendiri, tidak ada yang istimewa terjadi, Anda dapat misalnya memiliki NSArray27 objek, semua jenis objek yang berbeda, hanya 18 di antaranya memiliki metode -(void)setToBue;9 lainnya tidak. Jadi untuk memanggil setToBluesemua 18 yang perlu dilakukan, sesuatu seperti ini:

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

Hal lain tentang delegasi adalah bahwa mereka tidak disimpan, jadi Anda harus selalu mengatur delegasi nildalam MyClass deallocmetode Anda .

Tom Andersen
sumber
15

Sebagai praktik bagus yang direkomendasikan oleh Apple, ada baiknya bagi delegasi (yang merupakan protokol, menurut definisi), untuk menyesuaikan diri dengan NSObjectprotokol.

@protocol MyDelegate <NSObject>
    ...
@end

& untuk membuat metode opsional dalam delegasi Anda (yaitu metode yang tidak perlu diimplementasikan), Anda dapat menggunakan @optionalanotasi seperti ini:

@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

Jadi ketika menggunakan metode yang Anda tentukan sebagai opsional, Anda perlu (di kelas Anda) memeriksa respondsToSelectorapakah tampilan (yang sesuai dengan delegasi Anda) telah benar-benar menerapkan metode opsional Anda atau tidak.

Jean
sumber
11

Saya pikir semua jawaban ini masuk akal begitu Anda memahami delegasi. Secara pribadi saya datang dari tanah C / C ++ dan sebelum itu bahasa prosedural seperti Fortran dll jadi di sini saya 2 menit mengambil menemukan analog serupa dalam paradigma C ++.

Jika saya menjelaskan delegasi ke seorang programmer C ++ / Java saya akan mengatakan

Apa itu delegasi? Ini adalah pointer statis ke kelas dalam kelas lain. Setelah Anda menetapkan pointer, Anda dapat memanggil fungsi / metode di kelas itu. Karenanya beberapa fungsi kelas Anda "didelegasikan" (Dalam dunia C ++ pointer - ke oleh objek pointer kelas) ke kelas lain.

Apa itu protokol? Secara konseptual ini berfungsi sebagai tujuan yang sama dengan file header kelas yang Anda tetapkan sebagai kelas delegasi. Protokol adalah cara eksplisit untuk mendefinisikan metode apa yang perlu diimplementasikan di kelas yang penunjuknya ditetapkan sebagai delegasi dalam kelas.

Bagaimana saya bisa melakukan hal serupa di C ++? Jika Anda mencoba melakukan ini di C ++, Anda akan dengan mendefinisikan pointer ke kelas (objek) dalam definisi kelas dan kemudian menghubungkannya ke kelas lain yang akan menyediakan fungsi tambahan sebagai delegasi ke kelas dasar Anda. Tetapi kabel ini perlu dipertahankan dalam kode dan akan menjadi canggung dan rentan kesalahan. Objective C hanya mengasumsikan bahwa programmer tidak terbaik dalam mempertahankan decipline ini dan memberikan batasan compiler untuk menegakkan implementasi yang bersih.

DrBug
sumber
Yang Anda bicarakan adalah semantik sementara saya berbicara tentang intuisi. Apa yang Anda bicarakan adalah fungsi virtual - tetapi hanya untuk terbiasa dengan terminologi baru dapat menjadi hal yang menantang. Jawabannya melayani pemula yang ingin memikirkan paralell di C ++ / C
DrBug
Apa yang Anda katakan tidak terlalu jelas bagi saya. Mengapa Anda tidak menulis tanggapan baru dan mari kita lihat jika lebih banyak orang menganggapnya berguna, mereka akan memilihnya?
DrBug
9

Versi cepat

Delegasi hanyalah kelas yang melakukan beberapa pekerjaan untuk kelas lain. Baca kode berikut untuk contoh Playground yang agak konyol (tapi mudah-mudahan mencerahkan) yang menunjukkan bagaimana hal ini dilakukan di 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!"
}

Dalam praktik sebenarnya, delegasi sering digunakan dalam situasi berikut

  1. Ketika suatu kelas perlu mengkomunikasikan beberapa informasi ke kelas lain
  2. Ketika suatu kelas ingin memperbolehkan kelas lain untuk menyesuaikannya

Kelas-kelas tidak perlu tahu apa-apa tentang satu sama lain sebelumnya kecuali kelas delegasi sesuai dengan protokol yang diperlukan.

Saya sangat merekomendasikan membaca dua artikel berikut. Mereka membantu saya memahami delegasi bahkan lebih baik daripada dokumentasi .

Suragch
sumber
8

Ok, ini sebenarnya bukan jawaban untuk pertanyaan itu, tetapi jika Anda mencari cara untuk membuat delegasi Anda sendiri, mungkin sesuatu yang jauh lebih sederhana bisa menjadi jawaban yang lebih baik untuk Anda.

Saya hampir tidak mengimplementasikan delegasi saya karena saya jarang membutuhkannya. Saya dapat meminta HANYA SATU delegasi untuk objek delegasi. Jadi, jika Anda ingin delegasi Anda untuk komunikasi satu arah / data yang lewat daripada Anda jauh lebih baik dengan pemberitahuan.

NSNotification dapat meneruskan objek ke lebih dari satu penerima dan sangat mudah digunakan. Ini berfungsi seperti ini:

File MyClass.m akan terlihat seperti ini

#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

Untuk menggunakan pemberitahuan Anda di kelas lain: Tambahkan kelas sebagai pengamat:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherClassUpdatedItsData:) name:@"myClassUpdatedData" object:nil];

Terapkan pemilih:

- (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
}

Jangan lupa untuk menghapus kelas Anda sebagai pengamat jika

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
Tibidabo
sumber
8

katakanlah Anda memiliki kelas yang Anda kembangkan dan ingin mendeklarasikan properti delegasi untuk dapat memberitahukannya ketika beberapa peristiwa terjadi:

@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

jadi Anda mendeklarasikan protokol dalam MyClassfile header (atau file header terpisah), dan mendeklarasikan penangan event yang diperlukan / opsional yang harus / harus diimplementasikan oleh delegasi Anda, kemudian mendeklarasikan properti dalam MyClasstipe ( id< MyClassDelegate>) yang berarti setiap kelas objektif c yang sesuai dengan protokol MyClassDelegate, Anda akan melihat bahwa properti delegasi dinyatakan lemah, ini sangat penting untuk mencegah siklus mempertahankan (paling sering delegasi mempertahankan MyClassinstance jadi jika Anda menyatakan delegasi sebagai mempertahankan, keduanya akan mempertahankan satu sama lain dan tidak satu pun) dari mereka akan pernah dirilis).

Anda juga akan melihat bahwa metode protokol meneruskan MyClassinstance ke delegate sebagai parameter, ini adalah praktik terbaik jika delegasi ingin memanggil beberapa metode secara MyClassinstan dan juga membantu ketika delegasi menyatakan sendiri tentang MyClassDelegatebeberapa MyClassinstance, seperti ketika Anda memiliki banyak UITableView'scontoh di Anda ViewControllerdan menyatakan dirinya sebagai UITableViewDelegateuntuk mereka semua.

dan di dalam Anda, MyClassAnda memberi tahu delegasi dengan acara yang dinyatakan sebagai berikut:

if([_delegate respondsToSelector:@selector(myClass: requiredEventHandlerWithParameter:)])
{
     [_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}

Anda pertama kali memeriksa apakah delegasi Anda merespons metode protokol yang akan Anda panggil seandainya delegasi tidak mengimplementasikannya dan aplikasi akan macet (bahkan jika metode protokol diperlukan).

m.eldehairy
sumber
6

Berikut adalah metode sederhana untuk membuat delegasi

Buat Protokol dalam file .h. Pastikan itu didefinisikan sebelum protokol menggunakan @class diikuti dengan nama UIViewController< As the protocol I am going to use is UIViewController class>.

Langkah: 1: Buat Protokol kelas baru bernama "YourViewController" yang akan menjadi subkelas dari kelas UIViewController dan tetapkan kelas ini ke ViewController kedua.

Langkah: 2: Buka file "YourViewController" dan modifikasi seperti di bawah ini:

#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

Metode yang didefinisikan dalam perilaku protokol dapat dikontrol dengan @optional dan @required sebagai bagian dari definisi protokol.

Langkah: 3: Implementasi Delegasi

    #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

// uji apakah metode telah ditentukan sebelum Anda menyebutnya

 - (void) someMethodToCallDelegate {
     if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
           [self.delegate delegateMethodName:self]; 
     }
  }
soumya
sumber
5

Untuk membuat delegasi Anda sendiri, pertama-tama Anda perlu membuat protokol dan mendeklarasikan metode yang diperlukan, tanpa menerapkan. Dan kemudian mengimplementasikan protokol ini ke kelas header Anda di mana Anda ingin menerapkan metode delegate atau delegate.

Protokol harus dinyatakan sebagai berikut:

@protocol ServiceResponceDelegate <NSObject>

- (void) serviceDidFailWithRequestType:(NSString*)error;
- (void) serviceDidFinishedSucessfully:(NSString*)success;

@end

Ini adalah kelas layanan di mana beberapa tugas harus dilakukan. Ini menunjukkan cara mendefinisikan delegasi dan cara mengatur delegasi. Di kelas implementasi setelah tugas selesai delegasi metode dipanggil.

@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

Ini adalah kelas tampilan utama dari mana kelas layanan dipanggil dengan mengatur delegasi ke dirinya sendiri. Dan juga protokol diimplementasikan di kelas header.

@interface viewController: UIViewController <ServiceResponceDelegate>
{
ServiceClass* _service;
}

- (void) go;

@end

@implementation viewController

//
//some methods
//

- (void) go
{
_service = [[ServiceClass alloc] init];
[_service setDelegate:self];
[_service someTask];
}

Itu saja, dan dengan menerapkan metode delegasi di kelas ini, kontrol akan kembali setelah operasi / tugas selesai.

Mahesh
sumber
4

Penafian: ini adalah Swiftversi cara membuat delegate.

Jadi, apa yang dimaksud dengan delegasi? ... dalam pengembangan perangkat lunak, ada arsitektur solusi umum yang dapat digunakan kembali yang membantu untuk memecahkan masalah yang biasa terjadi dalam konteks yang diberikan, "template" ini, demikian, dikenal sebagai pola desain. Delegasi adalah pola desain yang memungkinkan satu objek untuk mengirim pesan ke objek lain ketika peristiwa tertentu terjadi. Bayangkan sebuah objek A memanggil objek B untuk melakukan suatu tindakan. Setelah tindakan selesai, objek A harus tahu bahwa B telah menyelesaikan tugas dan mengambil tindakan yang diperlukan, ini dapat dicapai dengan bantuan delegasi!

Untuk penjelasan yang lebih baik, saya akan menunjukkan kepada Anda cara membuat delegasi khusus yang mengirimkan data antar kelas, dengan Swift dalam aplikasi sederhana, mulai dengan mengunduh atau mengkloning proyek pemula ini dan menjalankannya!

Anda dapat melihat aplikasi dengan dua kelas, ViewController Adan ViewController B. B memiliki dua tampilan yang di tekan mengubah warna latar belakang ViewController, tidak ada yang terlalu rumit kan? nah sekarang mari kita berpikir dengan cara yang mudah untuk juga mengubah warna latar belakang kelas A ketika pandangan tentang kelas B diketuk.

Masalahnya adalah bahwa pandangan ini adalah bagian dari kelas B dan tidak tahu tentang kelas A, jadi kita perlu menemukan cara untuk berkomunikasi antara dua kelas ini, dan di situlah delegasi bersinar. Saya membagi implementasi menjadi 6 langkah sehingga Anda dapat menggunakan ini sebagai lembar contekan saat Anda membutuhkannya.

langkah 1: Cari tanda pragma langkah 1 dalam file ClassBVC dan tambahkan ini

//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}

Langkah pertama adalah membuat protocol, dalam hal ini, kami akan membuat protokol di kelas B, di dalam protokol Anda dapat membuat banyak fungsi yang Anda inginkan berdasarkan persyaratan implementasi Anda. Dalam hal ini, kami hanya memiliki satu fungsi sederhana yang menerima opsi UIColorsebagai argumen. Merupakan praktik yang baik untuk memberi nama protokol Anda dengan menambahkan kata delegatedi akhir nama kelas, dalam hal ini ClassBVCDelegate,.

langkah 2: Cari tanda pragma langkah 2 ClassVBCdan tambahkan ini

//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?

Di sini kita hanya membuat properti delegasi untuk kelas, properti ini harus mengadopsi protocoltipe, dan itu harus opsional. Selain itu, Anda harus menambahkan kata kunci yang lemah sebelum properti untuk menghindari siklus penyimpanan dan kebocoran memori potensial, jika Anda tidak tahu apa artinya itu jangan khawatir untuk saat ini, ingatlah untuk menambahkan kata kunci ini.

Langkah 3: Carilah tanda pragma langkah 3 dalam handleTap methoddi ClassBVCdan menambahkan ini

//MARK: step 3 Add the delegate method call here.
delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)

Satu hal yang harus Anda ketahui, jalankan aplikasi dan ketuk pada tampilan apa pun, Anda tidak akan melihat perilaku baru dan itu benar tetapi hal yang ingin saya tunjukkan adalah aplikasi itu tidak macet ketika delegasi dipanggil, dan itu karena kita membuatnya sebagai nilai opsional dan itulah mengapa itu tidak akan crash bahkan yang didelegasikan belum ada. Sekarang mari kita pergi ke ClassAVCfile dan membuatnya, yang didelegasikan.

langkah 4: Cari tanda pragma langkah 4 di dalam metode handleTap ClassAVCdan tambahkan ini di sebelah tipe kelas Anda seperti ini.

//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}

Sekarang ClassAVC mengadopsi ClassBVCDelegateprotokol, Anda dapat melihat bahwa kompiler Anda memberi Anda kesalahan yang mengatakan "Ketik 'ClassAVC tidak sesuai dengan protokol' ClassBVCDelegate 'dan ini hanya berarti bahwa Anda belum menggunakan metode protokol, bayangkan bahwa ketika kelas A mengadopsi protokol itu seperti menandatangani kontrak dengan kelas B dan kontrak ini mengatakan "Setiap kelas yang mengadopsi saya HARUS menggunakan fungsi saya!"

Catatan cepat: Jika Anda berasal dari Objective-Clatar belakang, Anda mungkin berpikir bahwa Anda juga dapat menutup kesalahan itu dengan membuat metode itu opsional, tetapi yang mengejutkan saya, dan mungkin milik Anda, Swiftbahasa tidak mendukung opsional protocols, jika Anda ingin melakukannya, Anda dapat membuat ekstensi untuk Anda protocolatau gunakan kata kunci @objc dalam protocolimplementasi Anda .

Secara pribadi, Jika saya harus membuat protokol dengan metode opsional yang berbeda, saya lebih suka memecahnya menjadi berbeda protocols, dengan cara itu saya akan mengikuti konsep memberikan satu tanggung jawab tunggal ke objek saya, tetapi dapat bervariasi berdasarkan pada implementasi spesifik.

di sini ada artikel bagus tentang metode opsional.

langkah 5: Cari tanda pragma langkah 5 di dalam metode persiapan untuk segue dan tambahkan ini

//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
}

Di sini kita hanya membuat instance ClassBVCdan menugaskan delegasinya untuk diri sendiri, tetapi apa itu diri di sini? yah, diri adalah ClassAVCyang telah didelegasikan!

langkah 6: Akhirnya, cari langkah pragma 6 ClassAVCdan mari kita gunakan fungsi protocol, mulai mengetik func changeBackgroundColor dan Anda akan melihat bahwa itu melengkapinya secara otomatis untuk Anda. Anda dapat menambahkan implementasi di dalamnya, dalam contoh ini, kami hanya akan mengubah warna latar belakang, tambahkan ini.

//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}

Sekarang jalankan aplikasinya!

Delegatesada di mana-mana dan Anda mungkin menggunakannya tanpa pemberitahuan, jika Anda membuat tableviewdelegasi di masa lalu yang Anda gunakan, banyak kelas UIKITpekerjaan di sekitar mereka dan banyak lainnya frameworksjuga, mereka memecahkan masalah utama ini.

  • Hindari kopling benda yang ketat.
  • Memodifikasi perilaku dan penampilan tanpa perlu mensubclass objek.
  • Izinkan tugas ditangani ke objek sembarang.

Selamat, Anda baru saja mengimplementasikan delegasi khusus, saya tahu Anda mungkin berpikir, begitu banyak masalah hanya untuk ini? baik, delegasi adalah pola desain yang sangat penting untuk dipahami jika Anda ingin menjadi iOSpengembang, dan selalu ingat bahwa mereka memiliki hubungan satu lawan satu antara objek.

Anda dapat melihat tutorial aslinya di sini

James Rochabrun
sumber
4

Jawaban sebenarnya dijawab, tetapi saya ingin memberi Anda "lembar contekan" untuk membuat delegasi:

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
Miras Maratuly
sumber
2

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;

Metode:

-(void)delegateMEthod: (ArgType) arg{
}
Lal Krishna
sumber
2

Dalam pandangan saya buat kelas terpisah untuk metode delegasi itu dan Anda dapat menggunakan di mana Anda inginkan.

di DropDownClass.h Kustom saya

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;

setelah itu file.m membuat array dengan objek,

 - (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];
        }
    }
}];
}

Di sini semua diatur untuk kelas delegasi Kustom. Setelah itu Anda dapat menggunakan metode delegasi ini di mana Anda inginkan. Misalnya ...

di impor viewcontroller saya yang lain setelah itu

buat tindakan untuk memanggil metode delegasi seperti ini

- (IBAction)dropDownBtn1Action:(id)sender {
DropDownViewController *vehicleModelDropView = [[DropDownViewController alloc]init];
vehicleModelDropView.dropDownType = DDCITY;
vehicleModelDropView.delegate = self;
[self presentViewController:vehicleModelDropView animated:YES completion:nil];
}

setelah itu panggil metode delegate seperti ini

- (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;
}
}
User558
sumber
0

Delegasi: - Buat

@protocol addToCartDelegate <NSObject>

-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;

@end

Kirim dan tolong tetapkan delegasi untuk melihat Anda mengirim data

[self.delegate addToCartAction:itemsModel isAdded:YES];
Vaibhav Gaikwad
sumber
0
//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. Menerapkan metode di kelas .m - (void) didRemoveCellWithTag: (NSInteger) tag {NSLog @ ("Tag% d", tag);

}

Rohit Kashyap
sumber
0

Mari kita mulai dengan sebuah contoh, jika kita membeli suatu produk secara online, ia akan melalui proses seperti pengiriman / pengiriman yang ditangani oleh tim yang berbeda. akan menjadi overhead untuk orang lain / vendor mungkin ingin meneruskan informasi ini hanya kepada orang-orang yang diperlukan.

Jadi jika kita berpikir dalam hal aplikasi kita, sebuah acara dapat menjadi pesanan online & tim yang berbeda bisa seperti banyak tampilan.

Berikut ini kode yang menganggap ShippingView sebagai tim Pengiriman & DeliveryView sebagai tim pengiriman:

//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
        //
    }
}
Ellen
sumber