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

661

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

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

Теги:
callback
delegates
cocoa

18 ответов

789
Лучший ответ

Участник 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 (в ARC) или assign (pre-ARC), чтобы избежать циклов сохранения, поскольку делегат объекта часто содержит сильную ссылку на этот объект. (Например, контроллер представления часто является делегатом представления, которое он содержит.)

Создание делегатов для ваших классов

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

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

Это аналогично интерфейсу или абстрактному базовому классу, так как в этом случае создается специальный тип для вашего делегата UIWebViewDelegate. Разработчики делегатов должны будут принять этот протокол:

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

И затем реализуйте методы в протоколе. Для методов, объявленных в протоколе как @optional (как и большинство методов делегатов), вам нужно проверить с помощью -respondsToSelector: перед вызовом определенного метода на нем.

Нейминг

Способы делегирования обычно называются именами, начинающимися с имени класса делегирования, и принимают делегирующий объект в качестве первого параметра. Они также часто используют волю, обязательную или простую форму. Итак, webViewDidStartLoad: (первый параметр - веб-представление), а не loadStarted (без каких-либо параметров).

Оптимизация скорости

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

@protocol SomethingDelegate <NSObject>
@optional
- (void)something:(id)something didFinishLoadingItem:(id)item;
- (void)something:(id)something didFailWithError:(NSError *)error;
@end

@interface Something : NSObject
@property (nonatomic, weak) id <SomethingDelegate> delegate;
@end

@implementation Something {
  struct {
    unsigned int didFinishLoadingItem:1;
    unsigned int didFailWithError:1;
  } delegateRespondsTo;
}
@synthesize delegate;

- (void)setDelegate:(id <SomethingDelegate>)aDelegate {
  if (delegate != aDelegate) {
    delegate = aDelegate;

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

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

Неофициальные делегаты

До того, как существовали протоколы, было общепринято использовать category в NSObject, чтобы объявить методы, которые может реализовать делегат. Например, CALayer все еще делает это:

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

Это по существу говорит компилятору, что любой объект может реализовать displayLayer:.

Затем вы использовали бы тот же подход -respondsToSelector:, как описано выше, для вызова этого метода. Делегаты просто реализуют этот метод и присваивают свойство delegate, и что он (там не объявляет, что вы соответствуете протоколу). Этот метод распространен в библиотеках Apple, но новый код должен использовать более современный подход к протоколу выше, поскольку этот подход загрязняет NSObject (что делает автозаполнение менее полезным) и затрудняет компилятору предупреждать вас об ошибках опечаток и подобных ошибках.

  • 0
    Я думаю, что вам нужно привести тип unsigned int к BOOL поскольку возвращаемое значение delegate respondsToSelector имеет тип BOOL .
  • 0
    Может ли делегат использоваться для полиморфизма, как в C ++?
Показать ещё 5 комментариев
336

Утвержденный ответ велик, но если вы ищете 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.m:

myClass.delegate = self;          //set its delegate to self somewhere

Внедрить метод делегирования

- (void) myClassDelegateMethod: (MyClass *) sender {
    NSLog(@"Delegates are great!");
}
  • 4
    Здорово использовать этот ответ в качестве краткого справочника. Но почему свойство делегата в вашем MyClass.h помечено как «IBOutlet»?
  • 4
    @ArnovanderMeer Хороший улов! Я не могу вспомнить почему. Мне нужно это в моем проекте, но не в этом примере, я удалил его. Спасибо
Показать ещё 10 комментариев
18

При использовании формального метода протокола для создания поддержки делегата я обнаружил, что вы можете обеспечить правильную проверку типов (хотя время выполнения, а не время компиляции), добавив что-то вроде:

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

в коде вашего делегата (setDelegate). Это помогает свести к минимуму ошибки.

17

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

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

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

  • FirstViewController реализует делегат (который предоставляет данные).
  • SecondViewController объявляет делегат (который будет получать данные).
16

Возможно, это больше похоже на то, что вам не хватает:

Если вы исходите из С++, например, точки зрения, делегаты немного привыкают - но в основном "они просто работают".

Как он работает, вы устанавливаете некоторый объект, который вы написали как делегат для NSWindow, но ваш объект имеет только реализации (методы) для одного или нескольких из многих возможных методов делегирования. Итак, что-то происходит, и NSWindow хочет вызвать ваш объект - он просто использует метод Objective-c respondsToSelector, чтобы определить, хочет ли ваш объект этот метод вызывать, а затем вызывает его. Вот как работает Objective-c - методы поиска по запросу.

Совершенно тривиально делать это с вашими собственными объектами, нет ничего особенного, вы можете, например, иметь NSArray из 27 объектов, всех разных видов объектов, только 18 из которых имеют метод -(void)setToBue; Остальные 9 нет. Таким образом, чтобы вызвать setToBlue для всех 18, которые нужно сделать, что-то вроде этого:

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

Другое дело о делегатах состоит в том, что они не сохраняются, поэтому вам всегда нужно назначить делегат nil в вашем методе MyClass dealloc.

15

В качестве хорошей практики, рекомендованной 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, если представление (соответствующее вашему делегату) фактически реализовало ваш дополнительный метод или нет.

9

Я думаю, что все эти ответы имеют большой смысл, когда вы понимаете делегатов. Лично я пришел из земли C/С++ и до этих процедурных языков, таких как Fortran и т.д., Вот и вот моя 2-минутная попытка найти аналогичные аналоги в парадигме С++.

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

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

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

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

  • 0
    То, о чем вы говорите, это семантика, когда я говорил об интуиции. То, о чем вы говорите, - это виртуальная функция, но просто привыкнуть к новой терминологии может быть непросто. Ответ служит новичкам, которые хотят думать о паралеле в C ++ / C
  • 0
    То, что вы говорите, мне не совсем понятно. Почему бы вам не написать свежий ответ, и давайте посмотрим, найдут ли другие люди его полезными, они проголосуют за него?
8

Быстрая версия

Делегат - это просто класс, который выполняет некоторую работу для другого класса. Прочитайте следующий код для несколько глупых (но, надеюсь, просветительских) примеров игровой площадки, которые показывают, как это делается в 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 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 work for him.
// bigBro tells lilSis to get him some water.
if let replyFromLilSis = bigBro.tellSomebodyToGetMeSomeWater() {
    print(replyFromLilSis) // "Go get it yourself!"
}

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

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

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

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

8

позволяет сказать, что у вас есть класс, который вы разработали, и хотите объявить свойство delegate, чтобы он мог уведомить его, когда происходит какое-то событие:

@class myClass;

@protocol myClassDelegate <NSObject>

-(void)myClass:(MyClass*)myObject requiredEventHandlerWithParameter:(ParamType*)param;

@optional
-(void)myClass:(MyClass*)myObject optionalEventHandlerWithParameter:(ParamType*)param;

@end


@interface MyClass : NSObject

@property(nonatomic,weak)id< MyClassDelegate> delegate;

@end

поэтому вы объявляете протокол в заголовочном файле MyClass (или отдельный заголовочный файл) и объявляете необходимые/необязательные обработчики событий, которые должен/должен выполнять ваш делегат, затем объявляйте свойство в MyClass типа (id< MyClassDelegate>), что означает любой объективный класс c, соответствующий протоколу MyClassDelegate, вы заметите, что свойство делегата объявлено слабым, это очень важно для предотвращения цикла сохранения (чаще всего делегат сохраняет экземпляр MyClass поэтому, если вы объявите делегата сохраненным, оба они сохранят друг друга, и ни один из них не будет выпущен).

вы также заметите, что методы протокола передают экземпляр MyClass делегату в качестве параметра, это наилучшая практика, если делегат хочет вызвать некоторые методы в экземпляре MyClass, а также помогает, когда делегат объявляет себя как MyClassDelegate для нескольких экземпляров MyClass, например, когда у вас есть несколько экземпляров UITableView's в ViewController и объявляет себя как UITableViewDelegate всем из них.

и внутри вашего MyClass вы сообщаете делегату с объявленными событиями следующим образом:

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

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

7

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

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

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

Вот простой способ создания делегатов

Создать протокол в .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]; 
     }
  }
4

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

Протокол должен быть объявлен ниже:

@protocol ServiceResponceDelegate <NSObject>

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

@end

Это класс обслуживания, в котором необходимо выполнить некоторую задачу. В нем показано, как определить делегат и как установить делегат. В классе реализации после завершения задачи делегат вызывает методы.

@interface ServiceClass : NSObject
{
id <ServiceResponceDelegate> _delegate;
}

- (void) setDelegate:(id)delegate;
- (void) someTask;

@end

@implementation ServiceClass

- (void) setDelegate:(id)delegate
{
_delegate = delegate;
}

- (void) someTask
{
/*

   perform task

*/
if (!success)
{
[_delegate serviceDidFailWithRequestType:@"task failed"];
}
else
{
[_delegate serviceDidFinishedSucessfully:@"task success"];
}
}
@end

Это основной класс представления, из которого вызывается класс службы, устанавливая делегат для себя. А также протокол реализован в классе заголовков.

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

- (void) go;

@end

@implementation viewController

//
//some methods
//

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

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

1

Отказ от ответственности: это версия Swift для создания делегата.

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

Для лучшего объяснения я покажу вам, как создать пользовательский делегат, который передает данные между классами, с Swift в простом приложении, начните с загрузки или клонирования этого стартового проекта и запустите его! https://github.com/jamesrochabrun/DelegateTutorial

Вы можете увидеть приложение с двумя классами: 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?)
}

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

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

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

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

Шаг 3: Найдите шаг 3 прагма-метки внутри метода handleTap в 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, вы можете видеть, что ваш компилятор дает вам сообщение об ошибке "Type" ClassAVC не соответствует протоколу ClassBVCDelegate, и это означает, что вы еще не использовали методы протокола, представьте себе что, когда класс A принимает протокол, это похоже на подписание контракта с классом B, и этот контракт гласит: "Любой класс, принимающий меня, ДОЛЖЕН использовать мои функции!"

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

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

вот хорошая статья о дополнительных методах. https://www.avanderlee.com/swift-2-0/optional-protocol-methods/

Шаг 5: Найдите шаг 5 прагма-метки внутри метода подготовки к методу 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 и назначаем его делегату самому себе, но что здесь собой? хорошо, self - это классAVC, который был делегирован!

Шаг 6: Наконец, найдите шаг 6 прагмы в ClassAVC и используйте функции протокола, начните вводить func changeBackgroundColor, и вы увидите, что его автозаполнение его для вас. Вы можете добавить любую реализацию внутри него, в этом примере мы просто изменим цвет фона, добавим это.

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

Теперь запустите приложение!

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

  • Избегайте жесткой связи объектов.
  • Измените поведение и внешний вид без необходимости подкласса объектов.
  • Разрешить выполнение задач для любого произвольного объекта.

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

Вы можете увидеть оригинальный учебник здесь https://medium.com/compileswift/implementing-delegates-in-swift-step-by-step-d3211cbac3ef

0

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

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

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

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

в моем Custom DropDownClass.h

typedef enum
{
 DDSTATE,
 DDCITY
}DropDownType;

@protocol DropDownListDelegate <NSObject>
@required
- (void)dropDownDidSelectItemWithString:(NSString*)itemString     DropDownType:(DropDownType)dropDownType;
@end
@interface DropDownViewController : UIViewController
{
 BOOL isFiltered;
}
@property (nonatomic, assign) DropDownType dropDownType;
@property (weak) id <DropDownListDelegate> delegate;
@property (strong, nonatomic) NSMutableArray *array1DropDown;
@property (strong, nonatomic) NSMutableArray *array2DropDown;

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

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat rowHeight = 44.0f;
return rowHeight;
}

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return isFiltered?[self.array1DropDown count]:[self.array2DropDown count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"TableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}

if (self.delegate) {
    if (self.dropDownType == DDCITY) {
        cell.textLabel.text = [self.array1DropDown objectAtIndex:indexPath.row];
    }
    else if (self.dropDownType == DDSTATE) {
        cell.textLabel.text = [self.array2DropDown objectAtIndex:indexPath.row];
    }
}
return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
 [self dismissViewControllerAnimated:YES completion:^{
    if(self.delegate){
        if(self.dropDownType == DDCITY){
            [self.delegate dropDownDidSelectItemWithString:[self.array1DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
        }
        else if (self.dropDownType == DDSTATE) {
            [self.delegate dropDownDidSelectItemWithString:[self.array2DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
        }
    }
}];
}

Здесь все заданы для пользовательского класса делегата. После этого вы можете использовать этот метод делегата, где хотите. Например...

в моем другом импорте viewcontroller после этого

создать действие для вызова метода делегирования, подобного этому

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

после этого метода делегирования вызова, подобного этому

- (void)dropDownDidSelectItemWithString:(NSString *)itemString DropDownType:(DropDownType)dropDownType {
switch (dropDownType) {
    case DDCITY:{
        if(itemString.length > 0){
            //Here i am printing the selected row
            [self.dropDownBtn1 setTitle:itemString forState:UIControlStateNormal];
        }
    }
        break;
    case DDSTATE: {
        //Here i am printing the selected row
        [self.dropDownBtn2 setTitle:itemString forState:UIControlStateNormal];
    }

    default:
        break;
}
}
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. Внедрить метод в классе .m - (Недействительными) didRemoveCellWithTag: (NSInteger) тег {  NSLog @( "Tag% d", тег);

}

0

ViewController.h

@protocol NameDelegate <NSObject>

-(void)delegateMEthod: (ArgType) arg;

@end

@property id <NameDelegate> delegate;

ViewController.m

[self.delegate delegateMEthod: argument];

MainViewController.m

ViewController viewController = [ViewController new];
viewController.delegate = self;

Метод:

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

Делегат: - Создать

@protocol addToCartDelegate <NSObject>

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

@end

Отправить и, пожалуйста, назначить делегата для просмотра, вы отправляете данные

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню