Делегат Objective-C - это объект, который был назначен delegateсвойству другого объекта. Чтобы создать его, вы определяете класс, который реализует интересующие вас методы делегата, и помечаете этот класс как реализующий протокол делегата.
Например, предположим, у вас есть UIWebView. Если вы хотите реализовать webViewDidStartLoad:метод его делегата , вы можете создать такой класс:
На UIWebViewстороне, вероятно, есть код, подобный этому, чтобы видеть, отвечает ли делегат на webViewDidStartLoad:сообщение, используя respondsToSelector:и отправляет его при необходимости.
Само свойство делегата обычно объявляется weak(в ARC) или assign(до ARC), чтобы избежать циклов сохранения, поскольку делегат объекта часто содержит сильную ссылку на этот объект. (Например, контроллер представления часто является делегатом представления, которое он содержит.)
Создание делегатов для ваших классов
Чтобы определить своих собственных делегатов, вам нужно где-то объявить их методы, как описано в Документах Apple по протоколам . Вы обычно объявляете официальный протокол. Объявление, перефразированное из UIWebView.h, будет выглядеть так:
@protocolUIWebViewDelegate<NSObject>@optional-(void)webViewDidStartLoad:(UIWebView*)webView;// ... other methods here@end
Это аналог интерфейса или абстрактного базового класса, так как UIWebViewDelegateв этом случае он создает специальный тип для вашего делегата . Разработчики делегата должны будут принять этот протокол:
@interfaceMyClass<UIWebViewDelegate>// ...@end
А затем реализовать методы в протоколе. Для методов, объявленных в протоколе как @optional(как и большинство методов делегатов), вы должны проверить -respondsToSelector:перед вызовом определенного метода для него.
Именование
Методы делегатов обычно именуются, начиная с имени делегирующего класса, и принимают делегирующий объект в качестве первого параметра. Они также часто используют волю, следует или сделали. Итак, webViewDidStartLoad:(первый параметр - это веб-представление), а не loadStarted(не принимая параметров), например.
Оптимизация скорости
Вместо того, чтобы проверять, отвечает ли делегат на селектор каждый раз, когда мы хотим отправить его, вы можете кэшировать эту информацию, когда установлены делегаты. Один очень чистый способ сделать это - использовать битовое поле, как показано ниже:
Затем в теле мы можем проверить, что наш делегат обрабатывает сообщения, обращаясь к нашей delegateRespondsToструктуре, а не отправляя -respondsToSelector:снова и снова.
Неофициальные делегаты
До появления протоколов, было принято использовать категорию на NSObjectдекларировать методы делегат мог бы осуществить. Например, CALayerвсе еще делает это:
@interfaceNSObject(CALayerDelegate)-(void)displayLayer:(CALayer*)layer;// ... other methods here@end
Это говорит компилятору, что любой объект может быть реализован displayLayer:.
Затем вы бы использовали тот же -respondsToSelector:подход, как описано выше, чтобы вызвать этот метод. Делегаты реализуют этот метод и присваивают delegateсвойство, и все (нет декларации о соответствии протоколу). Этот метод распространен в библиотеках Apple, но новый код должен использовать более современный протоколный подход, описанный выше, так как этот подход загрязняет NSObject(что делает автозаполнение менее полезным) и затрудняет компилятору предупреждение о опечатках и подобных ошибках.
Я думаю , что вам нужно , чтобы бросить unsigned intтип в BOOLкачестве возвращаемого значения delegate respondsToSelectorимеет типа BOOL.
Роланд
Может ли делегат использоваться для полиморфизма, как в C ++?
@ Дан Да, конечно. Протоколы вообще используются для полиморфизма.
Джесси Русак
@JesseRusak Я думаю, что «JSSomethingDelegate» должен быть «SomethingDelegate» для согласованности :)
Ханс Кнохель
382
Одобренный ответ хорош, но если вы ищете 1-минутный ответ, попробуйте это:
Файл MyClass.h должен выглядеть следующим образом (добавьте строки делегатов с комментариями!)
#import <BlaClass/BlaClass.h>@classMyClass;//define class, so protocol can see MyClass@protocolMyClassDelegate<NSObject>//define delegate protocol-(void) myClassDelegateMethod:(MyClass*) sender;//define delegate method to be implemented within another class@end//end protocol@interfaceMyClass:NSObject{}@property(nonatomic, weak) id <MyClassDelegate>delegate;//define MyClassDelegate as delegate@end
Файл MyClass.m должен выглядеть так
#import "MyClass.h"@implementationMyClass@synthesizedelegate;//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"@interfaceMyVC: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!");}
Здорово использовать этот ответ в качестве краткого справочника. Но почему свойство делегата в вашем MyClass.h помечено как «IBOutlet»?
Арно ван дер Меер
4
@ArnovanderMeer Хороший улов! Я не могу вспомнить почему. Мне нужно это в моем проекте, но не в этом примере, я удалил его. THX
Тибидабо
Спасибо. Каким бы приятным и тщательным ни был принятый ответ, я лучше учусь на некотором компактном примере кода. Хорошо иметь два ответа.
Судо
@Tibidabo Совершенно выдающийся. Мне бы очень хотелось, чтобы каждый мог объяснить такие концепции программирования. За эти годы я видел сотни объяснений о «делегатах» и никогда до сих пор не осознавал эту теорию! Большое вам спасибо ...
Чарльз Робертсон
5
Где myClassсоздается экземпляр внутри MyVC.m?
Лейн Реттиг
18
При использовании метода формального протокола для создания поддержки делегатов я обнаружил, что вы можете обеспечить правильную проверку типов (хотя и во время выполнения, а не во время компиляции), добавив что-то вроде:
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хочет вызвать ваш объект - он просто использует respondsToSelectorметод Objective-C, чтобы определить , хочет ли ваш объект вызвать этот метод, а затем вызывает его. Вот как работает target-c - методы ищутся по требованию.
Совершенно тривиально сделать это с вашими собственными объектами, ничего особенного в этом не происходит, например, вы можете иметь NSArray27 объектов, все виды объектов, только 18 из них имеют метод, -(void)setToBue;а другие 9 - нет. Итак, чтобы позвонить setToBlueвсем 18, которые нуждаются в этом, что-то вроде этого:
for(id anObject in myArray){if([anObject respondsToSelector:@selector(@"setToBlue")])[anObject setToBlue];}
Еще одна вещь, связанная с делегатами, заключается в том, что они не сохраняются, поэтому вы всегда должны устанавливать делегата nilв своем MyClass deallocметоде.
В соответствии с рекомендациями Apple, рекомендуется, чтобы делегат (который по определению является протоколом) соответствовал NSObjectпротоколу.
@protocolMyDelegate<NSObject>...@end
& чтобы создать дополнительные методы внутри вашего делегата (то есть методы, которые не обязательно должны быть реализованы), вы можете использовать @optionalаннотацию, подобную этой:
@protocolMyDelegate<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действительно ли представление (соответствующее вашему делегату) действительно реализовало ваш необязательный метод (ы) или нет.
Я думаю, что все эти ответы имеют большой смысл, когда вы понимаете делегатов. Лично я приехал из страны Си / Си ++ и до этого процедурных языков, таких как Фортран и т. Д., Так что вот моя 2-минутная попытка найти похожие аналоги в парадигме Си ++.
Если бы я должен был объяснить делегатов программисту на C ++ / Java, я бы сказал
Что такое делегаты? Это статические указатели на классы внутри другого класса. Как только вы назначите указатель, вы можете вызывать функции / методы в этом классе. Следовательно, некоторые функции вашего класса «делегируются» (в мире C ++ - указатель на указатель объекта класса) другому классу.
Какие протоколы? Концептуально это служит аналогичным назначением для файла заголовка класса, который вы назначаете в качестве класса делегата. Протокол - это явный способ определения того, какие методы должны быть реализованы в классе, указатель которого был задан как делегат внутри класса.
Как я могу сделать что-то подобное в C ++? Если бы вы попытались сделать это в C ++, вы должны определить указатели на классы (объекты) в определении класса, а затем связать их с другими классами, которые предоставят дополнительные функции в качестве делегатов вашему базовому классу. Но эта проводка должна поддерживаться в коде и будет неуклюжей и подверженной ошибкам. Цель C просто предполагает, что программисты не лучше всего поддерживают эту дешифровку, и предоставляет ограничения компилятора для обеспечения чистой реализации.
То, о чем вы говорите, - это семантика, когда я говорил об интуиции. То, о чем вы говорите, - это виртуальная функция, но просто привыкнуть к новой терминологии может быть непросто. Ответ предназначен для начинающих, которые хотят думать о паралеле в C ++ / C
DrBug
То, что вы говорите, мне не совсем понятно. Почему бы вам не написать свежий ответ, и давайте посмотрим, найдут ли другие люди его полезными, они проголосуют за него?
DrBug
9
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}classBossyBigBrother{// 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.returndelegate?.getYourNiceOlderSiblingAGlassOfWater()}}// PoorLittleSister conforms to the OlderSiblingDelegate protocolclassPoorLittleSister: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!"}
На практике делегаты часто используются в следующих ситуациях
Когда класс должен передать некоторую информацию другому классу
Когда класс хочет разрешить другому классу настроить его
Классы не должны знать ничего друг о друге заранее, за исключением того, что класс делегата соответствует требуемому протоколу.
Я настоятельно рекомендую прочитать следующие две статьи. Они помогли мне понять делегатов даже лучше, чем документация .
Хорошо, это не совсем ответ на вопрос, но если вы ищете, как сделать свой собственный делегат, возможно, что-то гораздо более простое может быть лучшим ответом для вас.
Я с трудом реализую своих делегатов, потому что мне это редко нужно. Я могу иметь ТОЛЬКО ОДИН делегат для объекта делегата. Так что если вы хотите, чтобы ваш делегат для односторонней связи / передачи данных, вам гораздо лучше с уведомлениями.
NSNotification может передавать объекты нескольким получателям, и им очень легко пользоваться. Это работает так:
Файл MyClass.m должен выглядеть так
#import "MyClass.h"@implementationMyClass-(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
Чтобы использовать ваше уведомление в других классах: Добавьте класс в качестве наблюдателя:
-(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 wantNSArray*otherClassData =[note userInfo][@"myClassData"];//get myClass data object and do whatever you want with it}
Не забудьте удалить свой класс в качестве наблюдателя, если
Допустим, у вас есть класс, который вы разработали, и вы хотите объявить свойство делегата, чтобы иметь возможность уведомлять его, когда происходит какое-то событие:
поэтому вы объявляете протокол в MyClassзаголовочном файле (или в отдельном заголовочном файле) и объявляете обязательные / необязательные обработчики событий, которые ваш делегат должен / должен реализовать, а затем объявляете свойство в MyClassтипе ( id< MyClassDelegate>), что означает любой целевой класс c, соответствующий По протоколу MyClassDelegateвы заметите, что свойство делегата объявлено как слабое, это очень важно для предотвращения сохранения цикла (чаще всего делегат сохраняет MyClassэкземпляр, поэтому, если вы объявили делегат как сохранение, оба они сохранят друг друга, и ни из них когда-нибудь выйдет).
Вы также заметите, что методы протокола MyClassпередают экземпляр делегату в качестве параметра, это наилучшая практика, если делегат хочет вызвать некоторые методы в MyClassэкземпляре, а также помогает, когда делегат объявляет себя MyClassDelegateдля нескольких MyClassэкземпляров, например, когда у вас несколько UITableView'sэкземпляры в вашем ViewControllerи объявляет себя UITableViewDelegateвсем им.
и внутри вашего MyClassвы уведомите делегата с объявленными событиями следующим образом:
сначала вы проверяете, отвечает ли ваш делегат на метод протокола, который вы собираетесь вызвать, в случае, если делегат не реализует его, а затем произойдет сбой приложения (даже если метод протокола требуется).
Создать протокол в .h файле. Убедитесь, что он определен перед протоколом с использованием @class, за которым следует имя UIViewController< As the protocol I am going to use is UIViewController class>.
Шаг: 1: Создайте новый протокол класса с именем «YourViewController», который будет подклассом класса UIViewController, и назначьте этот класс второму ViewController.
Шаг 2: перейдите к файлу «YourViewController» и измените его, как показано ниже:
#import <UIKit/UIkit.h>@classYourViewController;@protocolYourViewControllerDelegate<NSObject>@optional-(void)defineDelegateMethodName:(YourViewController*) controller;@required-(BOOL)delegateMethodReturningBool:(YourViewController*) controller;@end@interfaceYourViewController: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<YourViewControllerDelegate>delegate;@end
Методы, определенные в поведении протокола, могут управляться с помощью @optional и @required как часть определения протокола.
Шаг: 3: Реализация делегата
#import "delegate.h"@interfaceYourDelegateUser()<YourViewControllerDelegate>@end@implementationYourDelegateUser-(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 herereturn YES;}@end
// проверяем, был ли метод определен перед его вызовом
Чтобы создать свой собственный делегат, сначала нужно создать протокол и объявить необходимые методы, не реализуя. А затем внедрите этот протокол в свой класс заголовка, где вы хотите реализовать методы делегата или делегата.
Это класс обслуживания, где нужно выполнить какую-то задачу. Он показывает, как определить делегата и как установить делегата. В классе реализации после того, как задача выполнена, методы делегата вызываются.
Это основной класс представления, из которого вызывается класс обслуживания, устанавливая делегат для себя. А также протокол реализован в классе заголовка.
Отказ от ответственности: это Swiftверсия о том, как создать delegate.
Итак, что такое делегаты? … В разработке программного обеспечения существуют общие многократно используемые архитектуры решений, которые помогают решать часто возникающие проблемы в данном контексте, эти «шаблоны», так сказать, наиболее известны как шаблоны проектирования. Делегаты - это шаблон проектирования, который позволяет одному объекту отправлять сообщения другому объекту, когда происходит определенное событие. Представьте, что объект A вызывает объект B для выполнения действия. Как только действие завершено, объект A должен знать, что B выполнил задачу, и предпринять необходимые действия, это может быть достигнуто с помощью делегатов!
Вы можете увидеть приложение с двумя классами, ViewController Aи ViewController B. У Б есть два представления, что при нажатии меняет цвет фона ViewController, ничего слишком сложного, верно? Что ж, теперь давайте по-простому подумаем также изменить цвет фона класса A при касании представлений класса B.
Проблема заключается в том, что эти представления являются частью класса B и не имеют представления о классе A, поэтому нам нужно найти способ связи между этими двумя классами, и именно здесь сияет делегирование. Я разделил реализацию на 6 шагов, чтобы вы могли использовать ее как шпаргалку, когда вам это нужно.
Шаг 1: Найдите прагму в шаге 1 в файле ClassBVC и добавьте
Первым шагом является создание 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.classClassAVC:UIViewController,ClassBVCDelegate{}
Теперь, когда ClassAVC принял ClassBVCDelegateпротокол, вы можете видеть, что ваш компилятор выдает ошибку, которая говорит: «Тип» ClassAVC не соответствует протоколу «ClassBVCDelegate», и это только означает, что вы еще не использовали методы протокола, представьте, что когда класс A принимает протокол, это все равно что подписывать контракт с классом 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 -Wheredelegate is calling function
@protocol<#ProtocolName#> <NSObject>-(void)delegateMethod;@end@interface<#SomeViewController#> : <#UIViewController#> @property(nonatomic, assign) id <<#ProtocolName#>> delegate;@end@implementation<#SomeViewController#> -(void)someMethod {[self.delegate methodName];}@end
CLASS B -Wheredelegate is called
@interface<#OtherViewController#> (<#Delegate Name#>) {}@end@implementation<#OtherViewController#> -(void)otherMethod {
CLASSA *classA =[[CLASSA alloc] init];[classA setDelegate:self];}-delegateMethod(){}@end
-(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;}}
//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@interfaceMyClassUsesDelegate()<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 productsclassShippingView:UIView{
weak var delegate:ShippingDelegate?
var productID :String@IBAction func checkShippingStatus(sender:UIButton){// if product is shippeddelegate?.productShipped(productID: productID)}}//Delivery view which shows delivery status & tracking infoclassDeliveryView: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 statusclassProductViewController: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
//}}
Ответы:
Делегат Objective-C - это объект, который был назначен
delegate
свойству другого объекта. Чтобы создать его, вы определяете класс, который реализует интересующие вас методы делегата, и помечаете этот класс как реализующий протокол делегата.Например, предположим, у вас есть
UIWebView
. Если вы хотите реализоватьwebViewDidStartLoad:
метод его делегата , вы можете создать такой класс:Затем вы можете создать экземпляр MyClass и назначить его делегатом веб-представления:
На
UIWebView
стороне, вероятно, есть код, подобный этому, чтобы видеть, отвечает ли делегат наwebViewDidStartLoad:
сообщение, используяrespondsToSelector:
и отправляет его при необходимости.Само свойство делегата обычно объявляется
weak
(в ARC) илиassign
(до ARC), чтобы избежать циклов сохранения, поскольку делегат объекта часто содержит сильную ссылку на этот объект. (Например, контроллер представления часто является делегатом представления, которое он содержит.)Создание делегатов для ваших классов
Чтобы определить своих собственных делегатов, вам нужно где-то объявить их методы, как описано в Документах Apple по протоколам . Вы обычно объявляете официальный протокол. Объявление, перефразированное из UIWebView.h, будет выглядеть так:
Это аналог интерфейса или абстрактного базового класса, так как
UIWebViewDelegate
в этом случае он создает специальный тип для вашего делегата . Разработчики делегата должны будут принять этот протокол:А затем реализовать методы в протоколе. Для методов, объявленных в протоколе как
@optional
(как и большинство методов делегатов), вы должны проверить-respondsToSelector:
перед вызовом определенного метода для него.Именование
Методы делегатов обычно именуются, начиная с имени делегирующего класса, и принимают делегирующий объект в качестве первого параметра. Они также часто используют волю, следует или сделали. Итак,
webViewDidStartLoad:
(первый параметр - это веб-представление), а неloadStarted
(не принимая параметров), например.Оптимизация скорости
Вместо того, чтобы проверять, отвечает ли делегат на селектор каждый раз, когда мы хотим отправить его, вы можете кэшировать эту информацию, когда установлены делегаты. Один очень чистый способ сделать это - использовать битовое поле, как показано ниже:
Затем в теле мы можем проверить, что наш делегат обрабатывает сообщения, обращаясь к нашей
delegateRespondsTo
структуре, а не отправляя-respondsToSelector:
снова и снова.Неофициальные делегаты
До появления протоколов, было принято использовать категорию на
NSObject
декларировать методы делегат мог бы осуществить. Например,CALayer
все еще делает это:Это говорит компилятору, что любой объект может быть реализован
displayLayer:
.Затем вы бы использовали тот же
-respondsToSelector:
подход, как описано выше, чтобы вызвать этот метод. Делегаты реализуют этот метод и присваиваютdelegate
свойство, и все (нет декларации о соответствии протоколу). Этот метод распространен в библиотеках Apple, но новый код должен использовать более современный протоколный подход, описанный выше, так как этот подход загрязняетNSObject
(что делает автозаполнение менее полезным) и затрудняет компилятору предупреждение о опечатках и подобных ошибках.источник
unsigned int
тип вBOOL
качестве возвращаемого значенияdelegate respondsToSelector
имеет типаBOOL
.Одобренный ответ хорош, но если вы ищете 1-минутный ответ, попробуйте это:
Файл MyClass.h должен выглядеть следующим образом (добавьте строки делегатов с комментариями!)
Файл MyClass.m должен выглядеть так
Чтобы использовать ваш делегат в другом классе (в данном случае UIViewController называется MyVC) MyVC.h:
MyVC.m:
Реализуйте метод делегата
источник
myClass
создается экземпляр внутри MyVC.m?При использовании метода формального протокола для создания поддержки делегатов я обнаружил, что вы можете обеспечить правильную проверку типов (хотя и во время выполнения, а не во время компиляции), добавив что-то вроде:
в вашем коде доступа делегата (setDelegate). Это помогает минимизировать ошибки.
источник
Пожалуйста! посмотрите ниже простое пошаговое руководство, чтобы понять, как делегаты работают в iOS.
Я создал два ViewController (для отправки данных от одного к другому)
источник
Может быть, это больше похоже на то, что вам не хватает:
Если вы исходите из точки зрения, подобной C ++, делегатам нужно немного привыкнуть, но в основном «они просто работают».
Это работает так, что вы устанавливаете некоторый объект, который вы записали в качестве делегата в NSWindow, но у вашего объекта есть реализации (методы) только для одного или нескольких из множества возможных методов делегата. Итак, что-то происходит, и он
NSWindow
хочет вызвать ваш объект - он просто используетrespondsToSelector
метод Objective-C, чтобы определить , хочет ли ваш объект вызвать этот метод, а затем вызывает его. Вот как работает target-c - методы ищутся по требованию.Совершенно тривиально сделать это с вашими собственными объектами, ничего особенного в этом не происходит, например, вы можете иметь
NSArray
27 объектов, все виды объектов, только 18 из них имеют метод,-(void)setToBue;
а другие 9 - нет. Итак, чтобы позвонитьsetToBlue
всем 18, которые нуждаются в этом, что-то вроде этого:Еще одна вещь, связанная с делегатами, заключается в том, что они не сохраняются, поэтому вы всегда должны устанавливать делегата
nil
в своемMyClass dealloc
методе.источник
В соответствии с рекомендациями Apple, рекомендуется, чтобы делегат (который по определению является протоколом) соответствовал
NSObject
протоколу.& чтобы создать дополнительные методы внутри вашего делегата (то есть методы, которые не обязательно должны быть реализованы), вы можете использовать
@optional
аннотацию, подобную этой:Поэтому при использовании методов, которые вы указали как необязательные, вам необходимо (в вашем классе) проверить,
respondsToSelector
действительно ли представление (соответствующее вашему делегату) действительно реализовало ваш необязательный метод (ы) или нет.источник
Я думаю, что все эти ответы имеют большой смысл, когда вы понимаете делегатов. Лично я приехал из страны Си / Си ++ и до этого процедурных языков, таких как Фортран и т. Д., Так что вот моя 2-минутная попытка найти похожие аналоги в парадигме Си ++.
Если бы я должен был объяснить делегатов программисту на C ++ / Java, я бы сказал
Что такое делегаты? Это статические указатели на классы внутри другого класса. Как только вы назначите указатель, вы можете вызывать функции / методы в этом классе. Следовательно, некоторые функции вашего класса «делегируются» (в мире C ++ - указатель на указатель объекта класса) другому классу.
Какие протоколы? Концептуально это служит аналогичным назначением для файла заголовка класса, который вы назначаете в качестве класса делегата. Протокол - это явный способ определения того, какие методы должны быть реализованы в классе, указатель которого был задан как делегат внутри класса.
Как я могу сделать что-то подобное в C ++? Если бы вы попытались сделать это в C ++, вы должны определить указатели на классы (объекты) в определении класса, а затем связать их с другими классами, которые предоставят дополнительные функции в качестве делегатов вашему базовому классу. Но эта проводка должна поддерживаться в коде и будет неуклюжей и подверженной ошибкам. Цель C просто предполагает, что программисты не лучше всего поддерживают эту дешифровку, и предоставляет ограничения компилятора для обеспечения чистой реализации.
источник
Swift версия
Делегат - это просто класс, который выполняет работу для другого класса. Прочитайте следующий код для несколько глупого (но, надеюсь, поучительного) примера Playground, который показывает, как это делается в Swift.
На практике делегаты часто используются в следующих ситуациях
Классы не должны знать ничего друг о друге заранее, за исключением того, что класс делегата соответствует требуемому протоколу.
Я настоятельно рекомендую прочитать следующие две статьи. Они помогли мне понять делегатов даже лучше, чем документация .
источник
Хорошо, это не совсем ответ на вопрос, но если вы ищете, как сделать свой собственный делегат, возможно, что-то гораздо более простое может быть лучшим ответом для вас.
Я с трудом реализую своих делегатов, потому что мне это редко нужно. Я могу иметь ТОЛЬКО ОДИН делегат для объекта делегата. Так что если вы хотите, чтобы ваш делегат для односторонней связи / передачи данных, вам гораздо лучше с уведомлениями.
NSNotification может передавать объекты нескольким получателям, и им очень легко пользоваться. Это работает так:
Файл MyClass.m должен выглядеть так
Чтобы использовать ваше уведомление в других классах: Добавьте класс в качестве наблюдателя:
Реализуйте селектор:
Не забудьте удалить свой класс в качестве наблюдателя, если
источник
Допустим, у вас есть класс, который вы разработали, и вы хотите объявить свойство делегата, чтобы иметь возможность уведомлять его, когда происходит какое-то событие:
поэтому вы объявляете протокол в
MyClass
заголовочном файле (или в отдельном заголовочном файле) и объявляете обязательные / необязательные обработчики событий, которые ваш делегат должен / должен реализовать, а затем объявляете свойство вMyClass
типе (id< MyClassDelegate>
), что означает любой целевой класс c, соответствующий По протоколуMyClassDelegate
вы заметите, что свойство делегата объявлено как слабое, это очень важно для предотвращения сохранения цикла (чаще всего делегат сохраняетMyClass
экземпляр, поэтому, если вы объявили делегат как сохранение, оба они сохранят друг друга, и ни из них когда-нибудь выйдет).Вы также заметите, что методы протокола
MyClass
передают экземпляр делегату в качестве параметра, это наилучшая практика, если делегат хочет вызвать некоторые методы вMyClass
экземпляре, а также помогает, когда делегат объявляет себяMyClassDelegate
для несколькихMyClass
экземпляров, например, когда у вас несколькоUITableView's
экземпляры в вашемViewController
и объявляет себяUITableViewDelegate
всем им.и внутри вашего
MyClass
вы уведомите делегата с объявленными событиями следующим образом:сначала вы проверяете, отвечает ли ваш делегат на метод протокола, который вы собираетесь вызвать, в случае, если делегат не реализует его, а затем произойдет сбой приложения (даже если метод протокола требуется).
источник
Вот простой способ создания делегатов
Создать протокол в .h файле. Убедитесь, что он определен перед протоколом с использованием @class, за которым следует имя UIViewController
< As the protocol I am going to use is UIViewController class>.
Шаг: 1: Создайте новый протокол класса с именем «YourViewController», который будет подклассом класса UIViewController, и назначьте этот класс второму ViewController.
Шаг 2: перейдите к файлу «YourViewController» и измените его, как показано ниже:
Методы, определенные в поведении протокола, могут управляться с помощью @optional и @required как часть определения протокола.
Шаг: 3: Реализация делегата
// проверяем, был ли метод определен перед его вызовом
источник
Чтобы создать свой собственный делегат, сначала нужно создать протокол и объявить необходимые методы, не реализуя. А затем внедрите этот протокол в свой класс заголовка, где вы хотите реализовать методы делегата или делегата.
Протокол должен быть объявлен как ниже:
Это класс обслуживания, где нужно выполнить какую-то задачу. Он показывает, как определить делегата и как установить делегата. В классе реализации после того, как задача выполнена, методы делегата вызываются.
Это основной класс представления, из которого вызывается класс обслуживания, устанавливая делегат для себя. А также протокол реализован в классе заголовка.
Вот и все, и, реализовав методы делегата в этом классе, управление вернется после выполнения операции / задачи.
источник
Отказ от ответственности: это
Swift
версия о том, как создатьdelegate
.Итак, что такое делегаты? … В разработке программного обеспечения существуют общие многократно используемые архитектуры решений, которые помогают решать часто возникающие проблемы в данном контексте, эти «шаблоны», так сказать, наиболее известны как шаблоны проектирования. Делегаты - это шаблон проектирования, который позволяет одному объекту отправлять сообщения другому объекту, когда происходит определенное событие. Представьте, что объект A вызывает объект B для выполнения действия. Как только действие завершено, объект A должен знать, что B выполнил задачу, и предпринять необходимые действия, это может быть достигнуто с помощью делегатов!
Для лучшего объяснения я собираюсь показать вам, как создать пользовательский делегат, который передает данные между классами, с помощью Swift в простом приложении, начните с загрузки или клонирования этого начального проекта и запустите его!
Вы можете увидеть приложение с двумя классами,
ViewController A
иViewController B
. У Б есть два представления, что при нажатии меняет цвет фонаViewController
, ничего слишком сложного, верно? Что ж, теперь давайте по-простому подумаем также изменить цвет фона класса A при касании представлений класса B.Проблема заключается в том, что эти представления являются частью класса B и не имеют представления о классе A, поэтому нам нужно найти способ связи между этими двумя классами, и именно здесь сияет делегирование. Я разделил реализацию на 6 шагов, чтобы вы могли использовать ее как шпаргалку, когда вам это нужно.
Шаг 1: Найдите прагму в шаге 1 в файле ClassBVC и добавьте
Первым шагом является создание
protocol
, в этом случае мы создадим протокол в классе B, внутри протокола вы можете создать столько функций, сколько вам нужно, исходя из требований вашей реализации. В этом случае у нас просто есть одна простая функция, которая принимает необязательныйUIColor
аргумент. Это хорошая практика , чтобы назвать свои протоколы , добавив словоdelegate
в конце имени класса, в данном случаеClassBVCDelegate
.Шаг 2: Найдите прагматический шаг 2
ClassVBC
и добавьте этоЗдесь мы просто создаем свойство делегата для класса, это свойство должно принимать
protocol
тип, и оно должно быть необязательным. Кроме того, вы должны добавить ключевое слово слабое перед свойством, чтобы избежать циклов и потенциальных утечек памяти, если вы не знаете, что это значит, не беспокойтесь, просто не забудьте добавить это ключевое слово.шаг 3: Посмотрите на шаг Прагма марки 3 внутри handleTap
method
вClassBVC
и добавитьОдна вещь, которую вы должны знать, запустите приложение и нажмите на любое представление, вы не увидите никакого нового поведения, и это правильно, но я хочу отметить, что приложение не падает при вызове делегата, и это потому, что мы создаем его как необязательное значение, и поэтому оно не будет падать, даже если делегированный еще не существует. Теперь давайте перейдем к
ClassAVC
файлу и сделаем его делегированным.Шаг 4: Найдите шаг 4 прагмы внутри метода handleTap
ClassAVC
и добавьте его рядом с вашим типом класса следующим образом.Теперь, когда ClassAVC принял
ClassBVCDelegate
протокол, вы можете видеть, что ваш компилятор выдает ошибку, которая говорит: «Тип» ClassAVC не соответствует протоколу «ClassBVCDelegate», и это только означает, что вы еще не использовали методы протокола, представьте, что когда класс A принимает протокол, это все равно что подписывать контракт с классом B, и этот контракт говорит: «Любой класс, принимающий меня, ДОЛЖЕН использовать мои функции!»Краткое примечание. Если вы работаете в
Objective-C
фоновом режиме, вы, вероятно, думаете, что вы также можете закрыть эту ошибку, сделав этот метод необязательным, но, к моему удивлению и, вероятно,Swift
вашему , язык не поддерживает необязательныйprotocols
, если вы хотите это сделать, вы можете создать расширениеprotocol
или используйте ключевое слово @objc в своейprotocol
реализации.Лично, если мне нужно создать протокол с разными дополнительными методами, я бы предпочел разбить его на разные
protocols
, таким образом я буду следовать концепции предоставления единой ответственности моим объектам, но она может варьироваться в зависимости от конкретной реализации.Вот хорошая статья о дополнительных методах.
Шаг 5: Найдите прагматический знак шага 5 внутри метода подготовки к переходу и добавьте этот
Здесь мы просто создаем экземпляр класса
ClassBVC
и присваиваем его делегату себе, но что здесь есть я? ну, это то,ClassAVC
что было делегировано!Шаг 6: Наконец, найдите прагму на шаге 6,
ClassAVC
и давайте использовать функцииprotocol
, начнем вводить func changeBackgroundColor, и вы увидите, что он автоматически заполняется для вас. Вы можете добавить любую реализацию внутри него, в этом примере мы просто изменим цвет фона, добавим это.Теперь запустите приложение!
Delegates
находятся везде, и вы, вероятно, используете их даже без уведомления, если выtableview
в прошлом использовали делегирование, многие классыUIKIT
работ вокруг них и многие другиеframeworks
тоже решают эти основные проблемы.Поздравляю, вы просто внедрили собственный делегат, я знаю, что вы, вероятно, думаете, так много проблем только для этого? Ну, делегирование - это очень важный шаблон проектирования, который нужно понимать, если вы хотите стать
iOS
разработчиком, и всегда помнить о том, что они имеют отношение один к одному между объектами.Вы можете увидеть оригинальный учебник здесь
источник
Ответ действительно получен, но я хотел бы дать вам «шпаргалку» для создания делегата:
источник
ViewController.h
ViewController.m
MainViewController.m
Метод:
источник
На мой взгляд, создайте отдельный класс для этого метода делегата, и вы сможете использовать его там, где хотите.
в моем пользовательском DropDownClass.h
после этого в файле .m создайте массив с объектами,
Здесь все установлено для Пользовательского делегата класса. После этого вы можете использовать этот метод делегата, где вы хотите. Например ...
в моем другом импорте viewcontroller после этого
создать действие для вызова метода делегата, как это
после этого вызова метода делегата, как это
источник
Делегат: - Создать
Отправьте и, пожалуйста, назначьте делегата для просмотра отправляемых вами данных.
источник
// 5. Реализуйте метод в классе .m - (void) didRemoveCellWithTag: (NSInteger) tag {NSLog @ ("Tag% d", tag);
}
источник
Давайте начнем с примера: если мы покупаем продукт через Интернет, он проходит такой процесс, как доставка / доставка, осуществляемая различными командами. Так что, если доставка завершена, команда доставки должна уведомить команду доставки, и это должно быть сообщение один на один для передачи этой информации. Это может быть связано с накладными расходами для других людей / поставщик может захотеть передать эту информацию только нужным людям.
Поэтому, если мы думаем с точки зрения нашего приложения, мероприятие может быть онлайн-заказом, а разные команды могут быть похожи на несколько просмотров.
Вот код, который рассматривает ShippingView в качестве команды доставки и DeliveryView в качестве команды доставки:
источник