Как мне создать делегатов в Objective-C? - PullRequest
723 голосов
/ 09 марта 2009

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

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

Ответы [ 19 ]

7 голосов
/ 29 сентября 2015

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

Создать протокол в .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]; 
     }
  }
5 голосов
/ 03 августа 2015

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

Протокол должен быть объявлен следующим образом:

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

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

3 голосов
/ 26 апреля 2017

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

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

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

Вы можете увидеть приложение с двумя классами, ViewController A и ViewController 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, и оно должно быть необязательным. Кроме того, перед свойством необходимо добавить слабое ключевое слово, чтобы избежать циклов и возможных утечек памяти. Если вы пока не знаете, что это значит, не беспокойтесь, просто не забудьте добавить это ключевое слово.

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

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

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

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

шаг 5: найдите прагматический знак шага 5 внутри метода подготовки к переходу и добавьте это

//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 в 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 разработчиком, и всегда помнить, что они имеют отношение один к одному между объектами.

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

3 голосов
/ 16 марта 2018

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

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 голосов
/ 19 декабря 2016

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;

Метод: * +1010 *

-(void)delegateMEthod: (ArgType) arg{
}
1 голос
/ 08 февраля 2017

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

в моем 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;

после этого в файле ..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 голосов
/ 14 июля 2017

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

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

Вот код, который рассматривает 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 голосов
/ 02 января 2017
//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 @ ("Тег% d", тег);

}

0 голосов
/ 08 декабря 2016

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

@protocol addToCartDelegate <NSObject>

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

@end

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

[self.delegate addToCartAction:itemsModel isAdded:YES];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...