Как мне создать делегатов в Objective-C?
Я знаю, как работают делегаты, и я знаю, как я могу их использовать.
Но как мне их создать?
20 ответов
Делегат 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];
}
Само свойство делегата обычно объявляется 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:
снова и снова.
Неофициальные делегаты
До существования протоколов было принято использовать категорию 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.m:
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
хочет вызвать ваш объект - он просто использует Objective-C respondsToSelector
метод, чтобы определить, хочет ли ваш объект вызвать этот метод, а затем вызывает его. Вот как работает target-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.
Я создал два ViewController (для отправки данных от одного к другому)
- FirstViewController реализует делегат (который предоставляет данные).
- 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
если представление (которое соответствует вашему делегату) фактически реализовало ваш дополнительный метод (ы) или нет.
Swift версия
Делегат - это просто класс, который выполняет некоторую работу для другого класса. Прочитайте следующий код для несколько глупого (но, надеюсь, поучительного) примера Playground, который показывает, как это делается в 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!"
}
На практике делегаты часто используются в следующих ситуациях
- Когда класс должен передать некоторую информацию другому классу
- Когда класс хочет разрешить другому классу настроить его
Классы не должны знать ничего друг о друге заранее, за исключением того, что класс делегата соответствует требуемому протоколу.
Я настоятельно рекомендую прочитать следующие две статьи. Они помогли мне понять делегатов даже лучше, чем документация.
Я думаю, что все эти ответы имеют большой смысл, когда вы понимаете делегатов. Лично я приехал из страны Си / Си ++ и до этого процедурных языков, таких как Фортран и т. Д., Так что вот мои 2 минуты, чтобы найти аналогичные аналоги в парадигме Си ++.
Если бы я должен был объяснить делегатов программисту на C++/Java, я бы сказал,
Что такое делегаты? Это статические указатели на классы в другом классе. Как только вы назначите указатель, вы можете вызывать функции / методы в этом классе. Следовательно, некоторые функции вашего класса "делегируются" (в мире C++ - указатель на указатель объекта класса) другому классу.
Какие протоколы? Концептуально это служит аналогичным назначением для файла заголовка класса, который вы назначаете в качестве класса делегата. Протокол - это явный способ определения того, какие методы должны быть реализованы в классе, указатель которого был задан как делегат внутри класса.
Как я могу сделать что-то подобное в C++? Если бы вы попытались сделать это в C++, вы должны определить указатели на классы (объекты) в определении класса, а затем связать их с другими классами, которые будут предоставлять дополнительные функции в качестве делегатов для вашего базового класса. Но эта проводка должна поддерживаться в коде и будет неуклюжей и подверженной ошибкам. Цель C просто предполагает, что программисты не лучше всего поддерживают эту дешифровку, и предоставляет ограничения компилятора для обеспечения чистой реализации.
Хорошо, это не совсем ответ на вопрос, но если вы ищете, как сделать свой собственный делегат, возможно, что-то гораздо более простое может быть лучшим ответом для вас.
Я с трудом реализую своих делегатов, потому что мне это редко нужно. Я могу иметь ТОЛЬКО ОДИН делегат для объекта делегата. Так что, если вы хотите, чтобы ваш делегат для односторонней связи / передачи данных, вам гораздо лучше с уведомлениями.
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>
) что означает любой объективный класс c, соответствующий протоколу MyClassDelegate
вы заметите, что свойство делегата объявлено как слабое, это очень важно для предотвращения сохранения цикла (чаще всего делегат сохраняет MyClass
Например, если вы объявили делегата как сохраняющего, оба они сохранят друг друга, и ни один из них никогда не будет освобожден).
Вы также заметите, что методы протокола проходят MyClass
экземпляр делегату в качестве параметра, это наилучшая практика, если делегат хочет вызвать некоторые методы MyClass
экземпляр, а также помогает, когда делегат объявляет себя MyClassDelegate
на несколько MyClass
случаи, например, когда у вас есть несколько UITableView's
случаи в вашем ViewController
и заявляет о себе как UITableViewDelegate
всем им.
и внутри вашего MyClass
Вы уведомляете делегата о заявленных событиях следующим образом:
if([_delegate respondsToSelector:@selector(myClass: requiredEventHandlerWithParameter:)])
{
[_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}
Вы сначала проверяете, отвечает ли ваш делегат на метод протокола, который вы собираетесь вызвать, в случае, если делегат не реализует его, и тогда приложение будет аварийно завершать работу (даже если метод протокола требуется).
Чтобы создать свой собственный делегат, сначала нужно создать протокол и объявить необходимые методы, не реализуя. А затем внедрите этот протокол в свой класс заголовка, где вы хотите реализовать методы делегата или делегата.
Протокол должен быть объявлен как ниже:
@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];
}
Вот и все, и, реализовав методы делегата в этом классе, управление вернется после выполнения операции / задачи.
Вот простой способ создания делегатов
Создать протокол в.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];
}
}
Отказ от ответственности: это 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
типа, и это должно быть необязательно. Кроме того, перед свойством следует добавить слабое ключевое слово, чтобы избежать циклов и возможных утечек памяти. Если вы не знаете, что это значит, не беспокойтесь, просто не забудьте добавить это ключевое слово.
Шаг 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", и это означает только то, что вы еще не использовали методы протокола, представьте себе, что когда класс А принимает Протокол подобен подписанию контракта с классом B, и этот контракт гласит: "Любой усыновляющий меня класс ДОЛЖЕН использовать мои функции!"
Краткое примечание: если вы приехали из Objective-C
фон вы, вероятно, думаете, что вы также можете закрыть эту ошибку, делая этот метод необязательным, но, к моему удивлению, и, вероятно, ваш Swift
язык не поддерживает опционально protocols
, если вы хотите сделать это, вы можете создать расширение для вашего protocol
или используйте ключевое слово @objc в своем protocol
реализация.
Лично, если мне нужно создать протокол с различными дополнительными методами, я бы предпочел разбить его на разные 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
разработчик, и всегда имейте в виду, что они имеют один к одному отношения между объектами.
Вы можете увидеть оригинальный учебник здесь
Ответ действительно получен, но я хотел бы дать вам "шпаргалку" для создания делегата:
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
На мой взгляд, создайте отдельный класс для этого метода делегата, и вы можете использовать его там, где хотите.
в моем 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];
}
}
}];
}
Здесь все настроено для Custom делегата class.after, что вы можете использовать этот метод делегата, где вы хотите. Например...
в моем другом импорте 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;
}
}
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{
}
Делегат:- Создать
@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. Реализуйте метод в классе.m - (void) didRemoveCellWithTag: (NSInteger) tag {NSLog @ ("Tag% d", tag);
}
Давайте начнем с примера: если мы покупаем продукт через Интернет, он проходит такой процесс, как доставка / доставка, осуществляемая различными командами. Так что, если доставка завершена, команда доставки должна уведомить команду доставки, и это должно быть сообщение один на один, передающее эту информацию. Это может быть связано с накладными расходами для других людей / поставщик может захотеть передать эту информацию только нужным людям.
Так что, если мы думаем с точки зрения нашего приложения, мероприятие может быть онлайн-заказом, а разные команды могут быть похожи на несколько просмотров.
Вот код, который рассматривает 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
//
}
}
Картинка лучше тысячи слов :-P
Переменнаяgreeter
в функцииmain
кода Objective-C известен как делегат , который является не более чем указателем C++ на объект, который реализует класс чисто виртуальных функций.