Objective-C'de nasıl delege oluşturabilirim?


Yanıtlar:


889

Objective-C delegesi, delegateözelliğe başka bir nesne atanmış bir nesnedir. Bir tane oluşturmak için, ilgilendiğiniz temsilci yöntemlerini uygulayan bir sınıf tanımlarsınız ve bu sınıfı temsilci protokolünü uygularken olarak işaretlersiniz.

Örneğin, varsayalım UIWebView. Temsilcinin webViewDidStartLoad:yöntemini uygulamak isterseniz, şöyle bir sınıf oluşturabilirsiniz:

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

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

Daha sonra bir MyClass örneği oluşturabilir ve bunu web görünümünün temsilcisi olarak atayabilirsiniz:

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

Tarafta, UIWebViewmuhtemelen temsilcinin webViewDidStartLoad:iletiyi kullanarak yanıt verip vermediğini görmek respondsToSelector:ve buna uygun olarak göndermek için buna benzer bir kodu vardır .

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

Temsilci özelliğinin kendisi, döngüleri korumaktan kaçınmak için genellikle weak(ARC'de) veya assign(ARC öncesi ) bildirilir , çünkü bir nesnenin temsilcisi genellikle bu nesneye güçlü bir başvuruda bulunur. (Örneğin, bir görünüm denetleyicisi genellikle içerdiği bir görünümün temsilcisidir.)

Sınıflarınız için Delege Yapmak

Kendi delegelerinizi tanımlamak için , protokollerle ilgili Apple Dokümanlar'da tartışıldığı gibi yöntemlerini bir yerde bildirmeniz gerekir . Genellikle resmi bir protokol beyan edersiniz. UIWebView.h'den başka sözcüklerle açıklanan bildirim şöyle görünür:

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

Bu, bir temsilci veya soyut temel sınıfa benzer, çünkü UIWebViewDelegatebu durumda temsilciniz için özel bir tür oluşturur . Temsilci uygulayıcıların bu protokolü benimsemesi gerekir:

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

Ve sonra protokolde yöntemleri uygulayın. Protokolde @optional(çoğu delege yöntemi gibi) bildirilen yöntemler için, -respondsToSelector:belirli bir yöntemi çağırmadan önce kontrol etmeniz gerekir .

Adlandırma

Temsilci yöntemleri genellikle temsilci sınıf adıyla başlayarak adlandırılır ve temsilci nesneyi ilk parametre olarak alır. Ayrıca çoğu zaman bir irade, bir zorunluluk ya da bir yapı kullanırlar. Yani, webViewDidStartLoad:(ilk parametre web görünümüdür) yerine loadStarted(parametre almayan ) yerine .

Hız Optimizasyonu

Bir temsilci seçiciye her mesaj göndermek istediğimizde yanıt verip vermediğini kontrol etmek yerine, temsilciler ayarlandığında bu bilgileri önbelleğe alabilirsiniz. Bunu yapmanın çok temiz bir yolu, aşağıdaki gibi bir bitfield kullanmaktır:

@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

Daha sonra, vücutta, temsilcisimizin mesajları tekrar tekrar delegateRespondsTogöndermek yerine yapımıza erişerek kontrol ettiğini kontrol edebiliriz -respondsToSelector:.

Gayri Resmi Delegeler

Protokoller var önce, bir kullanımı yaygındı kategorisini üzerinde NSObjectbir temsilci uygulamak yöntemlerini ilan etmek. Örneğin, CALayeryine de bunu yapar:

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

Bu derleyiciye herhangi bir nesnenin uygulayabileceğini söyler displayLayer:.

Daha sonra -respondsToSelector:bu yöntemi çağırmak için yukarıda açıklananla aynı yaklaşımı kullanırsınız . Delegeler bu yöntemi uygular ve delegateözelliği atarlar ve hepsi budur (bir protokole uyduğunuzu beyan etmek yoktur). Bu yöntem Apple'ın kitaplıklarında yaygındır, ancak yeni kod yukarıdaki daha modern protokol yaklaşımını kullanmalıdır, çünkü bu yaklaşım NSObject(otomatik tamamlamayı daha az kullanışlı hale getirir) kirletir ve derleyicinin yazım hataları ve benzer hatalar konusunda sizi uyarmasını zorlaştırır.


Sana döküm gerek unsigned inttürünü BOOLdönüş değeri olarak delegate respondsToSelectortiptedir BOOL.
Roland

Delege, C ++ gibi Polimorfizm için kullanılabilir mi?

@Dan Evet, tabi. Genelde protokoller polimorfizm için kullanılır.
Jesse Rusak

@JesseRusak Bence "JSSomethingDelegate" tutarlılık için "SomethingDelegate" olmalı :)
Hans Knöchel

382

Onaylanan cevap harika, ancak 1 dakikalık bir cevap arıyorsanız şunu deneyin:

MyClass.h dosyası şöyle görünmelidir (açıklamalara delege satırları ekleyin!)

#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 dosyası şöyle görünmelidir

#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

Temsilcinizi başka bir sınıfta kullanmak için (bu durumda MyVC olarak adlandırılan 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

Delege yöntemini uygulama

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

4
Bu cevabı hızlı bir referans olarak kullanmak harika. Peki, MyClass.h dosyasındaki delege özelliği neden 'IBOutlet' olarak işaretlenmiş?
Arno van der Meer

4
@ArnovanderMeer İyi yakala! Nedenini hatırlayamıyorum. Projemde buna ihtiyacım var ama bu örnekte değil, kaldırdım. thx
Tibidabo

Teşekkürler. Kabul edilen cevap kadar güzel ve eksiksiz, en iyi bazı kompakt örnek koddan öğreniyorum. İki cevap almak güzel.
sudo

@Tibidabo Tamamen olağanüstü. Gerçekten herkesin bu gibi programlama kavramlarını açıklamasını isterdim. Yıllar boyunca 'delegeler' hakkında yüzlerce açıklama gördüm ve şimdiye kadar bu teoriyi hiç anlamadım! Çok teşekkür ederim ...
Charles Robertson

5
myClassMyVC.m içinde nereden somutlaştırılır?
Lane Rettig

18

Temsilci desteği oluşturmak için resmi protokol yöntemini kullanırken, gibi bir şey ekleyerek uygun tür denetleme (zaman olsa da, derleme değil zaman) sağlayabilirsiniz buldum:

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

delege erişimci (setDelegate) kodunuzda. Bu, hataları en aza indirmeye yardımcı olur.


18

Lütfen! Temsilcilerin iOS'ta nasıl çalıştığını anlamak için basit adım adım öğreticiyi kontrol edin.

İOS'ta temsilci seçme

İki ViewControllers oluşturdum (birinden diğerine veri göndermek için)

  1. FirstViewController uygulama temsilcisi (veri sağlar).
  2. SecondViewController temsilci beyan eder (veri alacaktır).

17

Belki de bu daha çok eksik olduğunuz şeylerdir:

C ++ benzeri bir bakış açısıyla geliyorsanız, delegeler biraz alışmaya başlar - ama temelde 'sadece çalışırlar'.

Çalışma şekli, NSWindow'a delege olarak yazdığınız bir nesneyi ayarlamanızdır, ancak nesnenizde birçok olası temsilci yönteminden yalnızca bir veya birkaçına yönelik uygulamalar (yöntemler) vardır. Bir şey olur ve NSWindownesnenizi çağırmak ister - respondsToSelectornesnenizin bu yöntemin çağrılmasını isteyip istemediğini belirlemek için Objective-c yöntemini kullanır ve sonra çağırır. Objektif-c böyle çalışır - talep üzerine yöntemler araştırılır.

Bunu kendi nesnelerinizle yapmak tamamen önemsizdir, özel bir şey yoktur, örneğin NSArray27 nesneden birine, her türlü nesneye sahip olabilirsiniz, sadece 18'inde -(void)setToBue;diğer 9'un yöntemi yoktur. setToBlueYapılması gereken 18'in tümünü çağırmak için, şöyle bir şey:

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

Delegelerle ilgili diğer bir şey, alıkonulmamasıdır, bu nedenle her zaman temsilci yönteminize ayarlamanız nilgerekir MyClass dealloc.


15

Apple tarafından önerilen iyi bir uygulama olarak, temsilcinin (tanım gereği bir protokol olan) NSObjectprotokole uyması iyidir .

@protocol MyDelegate <NSObject>
    ...
@end

& temsilciniz içinde isteğe bağlı yöntemler oluşturmak için (yani mutlaka uygulanması gerekmeyen yöntemler), @optionalek açıklamayı şu şekilde kullanabilirsiniz :

@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

Bu nedenle, isteğe bağlı olarak belirttiğiniz yöntemleri kullanırken, (sınıfınızda) respondsToSelectorgörünümün (temsilcinize uygun olan) gerçekten isteğe bağlı yöntem (ler) inizi uygulayıp uygulamadığını kontrol etmeniz gerekir.


11

Temsilcileri anladıktan sonra tüm bu cevapların çok anlamlı olduğunu düşünüyorum. Şahsen C / C ++ ülkesinden geldim ve Fortran vb. Gibi prosedürel dillerden önce C ++ paradigmasında benzer analogları bulmak için 2 dakikam.

Bir C ++ / Java programcısına delegeleri açıklayacak olsaydım

Delege nedir? Bunlar başka bir sınıf içindeki sınıflara statik işaretçilerdir. Bir işaretçi atadıktan sonra, o sınıftaki işlevleri / yöntemleri çağırabilirsiniz. Bu nedenle, sınıfınızın bazı işlevleri başka bir sınıfa "temsil edilir" (C ++ dünyasında - bir sınıf nesnesi işaretçisiyle işaretçi).

Protokoller nelerdir? Kavramsal olarak, delege sınıfı olarak atadığınız sınıfın başlık dosyasına benzer bir amaca hizmet eder. Protokol, sınıfta hangi yöntemlerin uygulanması gerektiğini tanımlamanın açık bir yoludur. İşaretçi sınıf içinde temsilci olarak ayarlanmıştır.

C ++ 'da benzer bir şeyi nasıl yapabilirim? Bunu C ++ 'da yapmaya çalışırsanız, sınıf tanımında sınıflara (nesnelere) işaretçiler tanımlayıp daha sonra bunları temel sınıfınıza delege olarak ek işlevler sağlayacak diğer sınıflara bağlayabilirsiniz. Ancak bu kablolamanın kod içinde düzeltilmesi gerekir ve beceriksiz ve hataya eğilimli olacaktır. Hedef C, programcıların bu dezavantajı sürdürmede en iyi olmadığını varsayar ve temiz bir uygulamayı uygulamak için derleyici kısıtlamaları sağlar.


Söylediğim şey sezgiden bahsederken anlambilimdir. Bahsettiğiniz şey sanal işlevdir - ancak sadece yeni terminolojiye alışmak zor olabilir. Cevap C ++ / C'de bir paralell düşünmek isteyen yeni başlayanlara hizmet ediyor
DrBug

Söylediklerin benim için gerçekten açık değil. Neden yeni bir yanıt yazmıyorsunuz ve daha fazla insanın yararlı bulup bulmayacağını görelim, oy verecekler mi?
DrBug

9

Hızlı sürüm

Bir temsilci sadece başka bir sınıf için çalışan bir sınıftır. Swift'te bunun nasıl yapıldığını gösteren biraz aptalca (ancak umarım aydınlatıcı) bir Oyun Alanı örneği için aşağıdaki kodu okuyun.

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

Gerçek uygulamada, delegeler aşağıdaki durumlarda sıklıkla kullanılır

  1. Bir sınıfın bazı bilgileri başka bir sınıfa iletmesi gerektiğinde
  2. Bir sınıf başka bir sınıfın onu özelleştirmesine izin vermek istediğinde

Sınıfların önceden delege sınıfının gerekli protokole uyması dışında birbirleri hakkında hiçbir şey bilmeleri gerekmez.

Aşağıdaki iki makaleyi okumanızı tavsiye ederim. Delegeleri belgelere göre daha iyi anlamama yardımcı oldular .


8

Tamam, bu gerçekten sorunun cevabı değil, ancak kendi delegenizi nasıl yapacağınızı arıyorsanız belki daha basit bir şey sizin için daha iyi bir cevap olabilir.

Delegelerimi zor uyguladım çünkü nadiren ihtiyacım var. Bir temsilci nesnesi için SADECE bir temsilci olabilir. Bu nedenle, temsilcinizin tek yönlü iletişim / veri iletmesini istiyorsanız, bildirimlerden çok daha iyidir.

NSNotification nesneleri birden fazla alıcıya aktarabilir ve kullanımı çok kolaydır. Şöyle çalışır:

MyClass.m dosyası şöyle görünmelidir

#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

Bildiriminizi başka bir sınıfta kullanmak için: Sınıfı gözlemci olarak ekleyin:

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

Seçiciyi uygulayın:

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

Eğer bir gözlemci olarak sınıfınızı kaldırmayı unutmayın

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

8

diyelim ki geliştirdiğiniz bir sınıfınız var ve bir etkinlik gerçekleştiğinde bunu bildirmek için bir temsilci özelliği bildirmek istiyorsunuz:

@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

böylece MyClassüstbilgi dosyasında (veya ayrı bir üstbilgi dosyasında) bir protokol bildirir ve temsilcinizin uygulaması / uygulaması gereken gerekli / isteğe bağlı olay işleyicilerini bildirirsiniz, sonra MyClasstür ( id< MyClassDelegate>) türünde bir özellik bildirir. protokol MyClassDelegate, temsilci özelliğinin zayıf olarak bildirildiğini fark edeceksiniz, bu tutma döngüsünü önlemek için çok önemlidir (çoğu zaman temsilci MyClassörneği korur, bu nedenle temsilci tutma olarak beyan ederseniz, her ikisi de birbirini korur ve hiçbiri bunlardan hiç çıkmayacak).

Ayrıca protokol yöntemlerinin MyClassörneği parametre olarak delegee geçirdiğini göreceksiniz. Bu, delegenin MyClassörnek olarak bazı yöntemleri çağırmak istemesi durumunda en iyi uygulamadır ve aynı zamanda temsilci, MyClassDelegatebirden çok MyClassörneğiniz gibi, UITableView'ssizin durumunuzda ViewControllerkendini UITableViewDelegategösterir ve hepsini hepsine bir olarak ilan eder .

ve MyClassbildirdiğiniz olayları temsilci ile aşağıdaki şekilde bilgilendirirsiniz:

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

ilk önce temsilci uygulamanız gereken protokol yöntemine yanıt verip vermediğini kontrol edersiniz ve temsilci uygulamadığı takdirde uygulama çökecektir (protokol yöntemi gerekli olsa bile).


6

İşte temsilci oluşturmak için basit bir yöntem

.H dosyasında Protokol oluşturun. @Class ve ardından UIViewController adının kullanıldığı protokolden önce tanımlandığından emin olun< As the protocol I am going to use is UIViewController class>.

Adım: 1: UIViewController sınıfının alt sınıfı olacak "YourViewController" adlı yeni bir sınıf Protokolü oluşturun ve bu sınıfı ikinci ViewController'a atayın.

Adım: 2: "YourViewController" dosyasına gidin ve aşağıdaki gibi değiştirin:

#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

Protokol davranışında tanımlanan yöntemler, protokol tanımının bir parçası olarak @optional ve @required ile kontrol edilebilir.

Adım: 3: Delege Uygulaması

    #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

// yöntem çağrılmadan önce tanımlanıp tanımlanmadığını test edin

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

5

Kendi temsilcinizi oluşturmak için, önce bir protokol oluşturmanız ve uygulama yapmadan gerekli yöntemleri bildirmeniz gerekir. Daha sonra bu protokolü, temsilci veya temsilci yöntemlerini uygulamak istediğiniz başlık sınıfınıza uygulayın.

Bir protokol aşağıdaki gibi beyan edilmelidir:

@protocol ServiceResponceDelegate <NSObject>

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

@end

Bu, bazı görevlerin yapılması gereken hizmet sınıfıdır. Temsilcinin nasıl tanımlanacağını ve temsilcinin nasıl ayarlanacağını gösterir. Uygulama sınıfında görev tamamlandıktan sonra delege yöntemleri çağrılır.

@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

Bu, temsilci kendisine ayarlanarak hizmet sınıfının çağrıldığı ana görünüm sınıfıdır. Ayrıca protokol başlık sınıfında uygulanır.

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

- (void) go;

@end

@implementation viewController

//
//some methods
//

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

Bu kadar ve bu sınıfta delege yöntemleri uygulayarak, işlem / görev tamamlandığında kontrol geri gelecektir.


4

Feragatname: Bu, Swiftnasıl oluşturulacağının sürümüdür delegate.

Delegeler nelerdir? … Yazılım geliştirmede, belirli bir bağlamda yaygın olarak ortaya çıkan sorunların çözülmesine yardımcı olan genel yeniden kullanılabilir çözüm mimarileri vardır, bu “şablonlar” tabiri caizse, en iyi tasarım modelleri olarak bilinir. Temsilciler, belirli bir olay gerçekleştiğinde bir nesnenin başka bir nesneye mesaj göndermesine izin veren bir tasarım modelidir. A nesnesinin bir eylemi gerçekleştirmek için B nesnesini çağırdığını düşünün. Eylem tamamlandığında, A nesnesi B'nin görevi tamamladığını bilmeli ve gerekli eylemi gerçekleştirmelidir, bu delegelerin yardımıyla gerçekleştirilebilir!

Daha iyi bir açıklama için, basit bir uygulamada Swift ile sınıflar arasında veri ileten özel bir temsilci oluşturmayı göstereceğim, bu başlangıç ​​projesini indirerek veya klonlayarak başlayın ve çalıştırın!

İki sınıflı bir uygulama görebilirsiniz ViewController Ave ViewController B. B, dokunduğunda arka plan rengini değiştiren iki görünüm var, ViewControllerçok karmaşık bir şey değil mi? şimdi de B sınıfına ilişkin görünümlere dokunulduğunda A sınıfının arka plan rengini değiştirmenin kolay bir yolunu düşünelim.

Sorun şu ki, bu görüşler B sınıfının bir parçası ve A sınıfı hakkında hiçbir fikre sahip değiller, bu yüzden bu iki sınıf arasında iletişim kurmanın bir yolunu bulmamız gerekiyor ve bu da delegasyonun parladığı yer. Uygulamayı 6 adıma böldüm, böylece ihtiyacınız olduğunda bunu bir hile sayfası olarak kullanabilirsiniz.

adım 1: ClassBVC dosyasında pragma işareti adım 1'i bulun ve ekleyin

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

İlk adım, protocolbu durumda, B sınıfında protokolü oluşturacağız, protokolün içinde, uygulamanızın gereksinimlerine göre istediğiniz kadar işlev oluşturabilirsiniz. Bu durumda, isteğe bağlı UIColorolarak argüman olarak kabul eden basit bir fonksiyonumuz var . delegateSınıf isminin sonuna sözcük ekleyerek protokollerinizi adlandırmak için iyi bir uygulamadır , bu durumda ClassBVCDelegate,.

2. adım: 2. adımdaki pragma işaretini arayın ClassVBCve ekleyin

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

Burada sadece sınıf için bir temsilci özelliği oluşturuyoruz, bu özellik protocoltürü benimsemeli ve isteğe bağlı olmalıdır. Ayrıca, koruma döngülerini ve potansiyel bellek sızıntılarını önlemek için mülkün önüne zayıf anahtar kelimeyi eklemelisiniz, bunun ne anlama geldiğini bilmiyorsanız, bu anahtar kelimeyi eklemeyi unutmayın.

3. adım: handleTap içindeki Pragma işareti 3. adımda için bak methodiçinde ClassBVCve bu ekleme

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

Bilmeniz gereken bir şey, uygulamayı çalıştırın ve herhangi bir görünüme dokunun, yeni bir davranış görmeyeceksiniz ve bu doğru ama işaret etmek istediğim şey, temsilci çağrıldığında uygulamanın çökmediği ve çünkü bunu isteğe bağlı bir değer olarak yaratıyoruz ve bu yüzden yetki verilenler bile çökmeyecek. Şimdi ClassAVCdosyaya gidip delege yapalım .

adim 4: handleTap yönteminin içindeki pragma işareti adımı 4'ü arayın ClassAVCve bunu böyle sınıf türünüzün yanına ekleyin.

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

Şimdi ClassAVC ClassBVCDelegateprotokolü kabul etti, derleyicinizin size “Type 'ClassAVC' ClassBVCDelegate 'protokolüne uymadığını söyleyen bir hata verdiğini görebilirsiniz ve bu sadece protokol yöntemlerini henüz kullanmadığınız anlamına gelir, A sınıfı protokolü kabul ettiğinde, B sınıfı ile bir sözleşme imzalamak gibidir ve bu sözleşme “Beni kabul eden herhangi bir sınıfın işlevlerimi KULLANMASI GEREKİR!” der.

Kısa not: Bir Objective-Carka plandan gelirseniz, muhtemelen bu yöntemi isteğe bağlı hale getiren bir hatayı da kapatabileceğinizi düşünüyorsunuz, ancak sürprizim ve muhtemelen sizin Swiftdiliniz için dil isteğe bağlı olarak desteklenmiyor protocols, eğer yapmak istiyorsanız oluşturabilirsiniz için bir uzantı protocolveya protocoluygulamanızda @objc anahtar sözcüğünü kullanın .

Şahsen, farklı isteğe bağlı yöntemlerle bir protokol oluşturmak zorunda kalırsam, onu farklı hale getirmeyi tercih ederim protocols, bu şekilde nesnelerime tek bir sorumluluk verme kavramını takip edeceğim, ancak belirli uygulamaya bağlı olarak değişebilir.

İşte isteğe bağlı yöntemler hakkında iyi bir makale.

adım 5: segue yöntemine hazırlanmanın içindeki pragma işareti adım 5'i arayın ve ekleyin

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

Burada sadece bir örneğini oluşturup ClassBVCtemsilcisini kendimize atarız, ama burada benlik nedir? Eh, ClassAVCdelege edilen kendiliktir !

adım 6: Son olarak, pragma adım 6'yı arayın ClassAVCve işlevlerini kullanalım, protocolfunc changeBackgroundColor yazmaya başlayın ve bunun sizin için otomatik olarak tamamlandığını göreceksiniz. İçine herhangi bir uygulama ekleyebilirsiniz, bu örnekte, sadece arka plan rengini değiştireceğiz, bunu ekleyeceğiz.

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

Şimdi uygulamayı çalıştırın!

Delegatesher yerde ve muhtemelen haber vermeden kullanırsınız tableview, geçmişte bir delegasyon kullandıysanız, UIKITetraflarında birçok çalışma sınıfı ve daha birçoğu oluşturursanız frameworks, bu ana sorunları çözerler.

  • Nesneleri sıkıca birleştirmekten kaçının.
  • Nesneleri alt sınıflamaya gerek kalmadan davranış ve görünümü değiştirin.
  • Görevlerin herhangi bir keyfi nesneye uygulanmasına izin verin.

Tebrikler, sadece özel bir delege uyguluyorsunuz, muhtemelen düşündüğünüzü biliyorum, sadece bunun için çok fazla sorun mu var? temsilci, iOSgeliştirici olmak isteyip istemediğinizi anlamak için çok önemli bir tasarım modelidir ve nesneler arasında bire bir ilişkilerinin olduğunu her zaman aklınızda bulundurun.

Orijinal öğreticiyi burada görebilirsiniz


4

Cevap aslında cevaplandı, ancak bir temsilci oluşturmak için size bir "hile sayfası" vermek istiyorum:

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

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;

Yöntem:

-(void)delegateMEthod: (ArgType) arg{
}

2

Benim açımdan o temsilci yöntemi için ayrı bir sınıf oluşturun ve istediğiniz yerde kullanabilirsiniz.

Özel DropDownClass.h dosyamda

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;

bundan sonra in.m dosyasında nesnelerle dizi oluşturma,

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

Tümü Özel temsilci sınıfı için ayarlanmıştır. Bundan sonra istediğiniz yerde bu temsilci yöntemini kullanabilirsiniz. Örneğin ...

ondan sonra başka bir viewcontroller ithalat benim

delege yöntemini çağırmak için eylem oluştur

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

bundan sonra delege yöntemini şöyle çağır

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

0

Temsilci: - Oluştur

@protocol addToCartDelegate <NSObject>

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

@end

Gönder ve lütfen veri gönderdiğinizi görüntülemek için temsilci atayın

[self.delegate addToCartAction:itemsModel isAdded:YES];

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. Yöntemi sınıfında uygulayın. M - (void) didRemoveCellWithTag: (NSInteger) etiketi {NSLog @ ("Etiket% d", etiket);

}


0

Çevrimiçi olarak bir ürün satın alırsak, bir örnekle başlayalım, farklı ekipler tarafından taşınan nakliye / teslimat gibi bir süreçten geçer.Gönderim tamamlanırsa, nakliye ekibi teslimat ekibini bilgilendirmeli ve bu bilgileri yayınlayan birebir iletişim olmalıdır. başkaları için ek yük / satıcı bu bilgileri sadece gerekli kişilere iletmek isteyebilir.

Uygulamamız açısından düşünürsek, bir etkinlik çevrimiçi sipariş olabilir ve farklı ekipler birden çok görüntüleme gibi olabilir.

İşte kodu ShippingView'i Nakliye ekibi olarak düşünün ve DeliveryView'u dağıtım ekibi olarak düşünün:

//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
        //
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.