Как создать делегатов в Objective-C?

Я знаю, как работают делегаты, и я знаю, как я могу их использовать.

но как их создать?

19 ответов


делегат 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];
}

обычно объявляется само свойство delegate weak (по дуге) или assign (pre-ARC), чтобы избежать циклов сохранения, так как делегат объекта часто содержит сильную ссылку на этот объект. (Например, контроллер представления часто является делегатом представления, которое он содержит.)

делегаты для классов

чтобы определить своих делегатов, вам придется где-то объявить их методы, как обсуждалось в документы Apple по протоколам. Обычно вы объявляете официальный протокол. Заявление, перефразированное из UIWebView.ч, будет выглядеть так:

@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 struct, а не путем отправки -respondsToSelector: снова и снова.

Неофициальных Делегатов

до того, как протоколы существовали, было принято использовать категория on 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

использовать ваш делегат в другом классе (UIViewController называется MyVC в этом случае) MyVC.h:

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

MyVC.м:

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 хочет вызвать ваш объект - он просто использует Цель-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.

делегировать в iOS

Я создал два ViewControllers (для отправки данных от одного к другому)

  1. делегат реализации FirstViewController (который предоставляет данные).
  2. 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 и т. д. Вот мой 2-минутный поиск аналогичных аналогов в парадигме c++.

Если бы я должен был объяснить делегатов программисту C++ / Java, я бы сказал

Что такое делегаты ? Это статические указатели на классы внутри другого класса. После назначения указателя вы можете вызывать функции / методы в этот класс. Следовательно, некоторые функции вашего класса "делегированы" (в C++ world - указатель на указатель объекта класса) другому классу.

Что такое протоколы ? Концептуально он служит той же цели, что и файл заголовка класса, который вы назначаете в качестве класса делегата. Протокол-это явный способ определения того, какие методы должны быть реализованы в классе, указатель которого был установлен как делегат в классе.

Как я могу сделать что-то подобное в C++? Если вы попытавшись сделать это на C++, вы бы определили указатели на классы (объекты) в определении класса, а затем подключили их к другим классам, которые будут предоставлять дополнительные функции в качестве делегатов вашего базового класса. Но эта проводка должна быть maitained в коде и будет неуклюжей и подвержена ошибкам. Цель C просто предполагает, что программисты не лучше поддерживают эту decipline и предоставляет ограничения компилятора для обеспечения чистой реализации.


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

на практике, делегаты часто используются в следующих ситуациях

  1. когда класс должен передать некоторую информацию другому классу
  2. когда класс хочет разрешить другому классу настроить его

классам не нужно ничего знать друг о друге заранее, за исключением того, что класс делегата соответствует требуемому протоколу.

я настоятельно рекомендую прочитать следующие две статьи. Они помогли мне понять делегатов даже лучше, чем документация сделал.


ок, это не совсем ответ на вопрос, но если вы ищете, как сделать свой собственный делегат может быть что-то гораздо проще может быть лучшим ответом для вас.

Я вряд ли реализую своих делегатов, потому что мне редко нужно. У меня может быть только один делегат для объекта delegate. Поэтому, если вы хотите, чтобы ваш делегат для односторонней связи / передачи данных, чем вы намного лучше с уведомлениями.

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>) что означает любой класс objective c, который соответствует протоколу MyClassDelegate , вы заметите, что свойство delegate объявляется слабым , это очень важно для предотвращения цикла сохранения (чаще всего делегат сохраняет 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 : создайте новый протокол класса с именем "YourViewController", который будет подклассом класса UIViewController и назначит этот класс второму 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

Это основной класс представления, из которого класс службы вызывается путем установки делегата самому себе. А также протокол реализован в классе 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];
}

вот и все, и, реализуя методы делегата в этом классе, контроль вернется, как только операция/задача будет выполнена.


отказ от ответственности: это Swift версия того, как создать delegate.

Итак, что такое делегаты? ...в разработке программного обеспечения есть общие многоразовые архитектуры решений, которые помогают решать часто возникающие проблемы в данном контексте, эти "шаблоны", так сказать, наиболее известны как шаблоны проектирования. Делегаты-это шаблон проектирования, который позволяет одному объекту отправлять сообщения другому объекту при возникновении определенного события. Представьте, что объект A вызывает объект B для выполнить действие. Как только действие завершено, объект A должен знать, что B выполнил задачу и принять необходимые меры, это может быть достигнуто с помощью делегатов!

для лучшего объяснения я покажу вам, как создать пользовательский делегат, который передает данные между классами, с помощью Swift в простом приложении,начните с загрузки или клонирования этого стартового проекта и запустите его!

вы можете увидеть приложение с двумя классами, ViewController A и ViewController B. B имеет два вида, которые при нажатии меняет цвет фона ViewController ничего не слишком сложно? теперь давайте подумаем, как легко изменить цвет фона класса A, когда взгляды на класс B прослушиваются.

проблема в том, что эти представления являются частью класса B и понятия не имеют о классе A, поэтому нам нужно найти способ общения между этими двумя классами, и именно там делегирование сияет. Я разделил реализацию на 6 шагов, чтобы вы могли использовать это как шпаргалка, когда вам это нужно.

Шаг 1: Найдите Шаг 1 метки прагмы в файле ClassBVC и добавьте это

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

первым шагом является создание protocol, в этом случае мы создадим протокол в классе B, внутри протокола вы можете создать столько функций, сколько хотите, на основе требований вашей реализации. В этом случае у нас есть только одна простая функция, которая принимает необязательный UIColor в качестве аргумента. Это хорошая практика, чтобы назвать ваши протоколы добавляют слово delegate в конце имени класса, в данном случае, ClassBVCDelegate.

Шаг 2: найдите знак прагмы Шаг 2 в ClassVBC и добавить этот

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

здесь мы просто создаем свойство делегата для класса, это свойство должно принять protocol тип, и это должно быть факультативным. Кроме того, вы должны добавить ключевое слово weak перед свойством, чтобы избежать циклов сохранения и потенциальных утечек памяти, если вы не знаете, что это значит, не беспокойтесь теперь, просто не забудьте добавить это ключевое слово.

Шаг 3: Найдите метку pragma Шаг 3 внутри handleTap method на ClassBVC и добавить этот

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

одна вещь, которую вы должны знать, запустите приложение и нажмите на любой вид, вы не увидите никакого нового поведения, и это правильно, но то, что я хочу отметить, что приложение не сбой, когда вызывается делегат, и это потому, что мы создаем его как необязательное значение, и именно поэтому он не будет сбой даже в приложении. делегирование еще не существует. Теперь перейдем к ClassAVC файл и сделать это, делегированный.

Шаг 4: Найдите Шаг 4 метки прагмы внутри метода handleTap в ClassAVC и добавьте это рядом с вашим типом класса, как это.

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

теперь ClassAVC принял ClassBVCDelegate протокол, вы можете видеть, что ваш компилятор дает вам ошибку, которая говорит: "тип" ClassAVC не соответствует протоколу " ClassBVCDelegate’ , и это только означает, что вы не использовали методы представьте себе, что, когда класс А принимает протокол, это все равно что подписать контракт с классом В, и в этом контракте говорится: "любой класс, принимающий меня, должен использовать мои функции!"

быстрое Примечание: Если вы пришли из Objective-C фон вы, вероятно, думаете, что вы также можете заткнуться, что ошибка делает этот метод необязательным, но для моего удивления, и, вероятно, ваш,Swift язык не поддерживает дополнительно protocols, если вы хотите сделать это, вы можете создать расширение для своего protocol или используйте ключевое слово @objc в своем protocol реализация.

лично, если мне нужно создать протокол с различными дополнительными методами, я бы предпочел разбить его на разные protocols, таким образом, я буду следовать концепции предоставления одного ответственность за свои объекты, но оно может варьироваться в зависимости от конкретной реализации.

здесь хорошая статья о дополнительных способах.

Шаг 5: найдите знак прагмы Шаг 5 внутри метод prepare for segue и добавьте это

//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 и назначьте своего делегата себе, но что такое " я " здесь? ну, я-это ClassAVC, который был делегирован!

Шаг 6: наконец, найдите Шаг 6 pragma в 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 разработчик, и всегда имейте в виду, что у них есть один к одному отношения между объектами.

вы можете увидеть оригинальный учебник здесь


ViewController.h

@protocol NameDelegate <NSObject>

-(void)delegateMEthod: (ArgType) arg;

@end

@property id <NameDelegate> delegate;

ViewController.м

[self.delegate delegateMEthod: argument];

MainViewController.м

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;

после этого в.файл м создать массив с объектами,

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

Делегат: - Create

@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. Реализуйте метод в классе .м - (void)didRemoveCellWithTag: (NSInteger)тег { NSLog@("тег %d", тег);

}


давайте начнем с примера, если мы покупаем продукт онлайн, он проходит через процесс, как доставка/доставка обрабатывается различными командами.Поэтому, если доставка будет завершена, команда доставки должна уведомить команду доставки, и она должна быть одна к одной связи, поскольку трансляция этой информации будет накладной для других людей / поставщик может захотеть передать эту информацию только требуемым людям.

поэтому, если мы думаем с точки зрения нашего приложения, событие может быть онлайн-заказ и разных команд может быть как несколько видов.

вот код рассмотрите 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
        //
    }
}

ответ на самом деле ответил, но я хотел бы дать вам "шпаргалку" для создания делегата:

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