Jeg vet hvordan delegater fungerer, og jeg vet hvordan jeg kan bruke dem.
Men hvordan skaper jeg dem?
Jeg vet hvordan delegater fungerer, og jeg vet hvordan jeg kan bruke dem.
Men hvordan skaper jeg dem?
En Objective-C representant er et objekt som har blitt tildelt til den delegateegenskapen et annet objekt. For å opprette en, du bare definere en klasse som implementerer representanten metoder du er interessert i, og markere at klassen som implementerer representanten protokollen.
For eksempel si at du har en UIWebView. Hvis du ønsker å gjennomføre sin representantens webViewDidStartLoad:metoden, kan du lage en klasse som dette:
@interface MyClass<UIWebViewDelegate>
// ...
@end
@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView {
// ...
}
@end
Deretter kan du opprette en forekomst av MyClass og tildele det som web visning delegat:
MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;
På den UIWebViewsiden, har det sannsynligvis kode som ligner på dette for å se om representanten reagerer på webViewDidStartLoad:meldingen med respondsToSelector:og sende den om nødvendig.
if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
}
Denne representanten egenskap i seg selv vanligvis er deklarert weak(i ARC) eller assign(pre-ARC) for å unngå beholde sløyfer, ettersom representanten for et objekt ofte har en sterk referanse til den aktuelle gjenstand. (For eksempel er et riss controller ofte representanten av en visning den inneholder.)
Å definere dine egne delegater, må du deklarere sine metoder eller annet sted, som omtalt i Apple Dokumenter på protokoller . Du erklærer vanligvis en formell protokoll. Erklæringen, omskrevet fra UIWebView.h, vil se slik ut:
@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end
Dette er analogt til et grensesnitt eller abstrakt base klasse, som det skaper en spesiell type for delegat, UIWebViewDelegatei dette tilfellet. Delegat implementors måtte vedta denne protokollen:
@interface MyClass <UIWebViewDelegate>
// ...
@end
Og deretter implementere metodene i protokollen. For metoder deklarert i protokollen som @optional(som de fleste delegere metoder), må du sjekke med -respondsToSelector:før du ringer en bestemt metode på den.
Delegatenfremgangsmåter er vanligvis navngitt som starter med oppdrags et klassenavn og ta oppdrags gjenstanden som den første parameter. De har også ofte en villighet, should- eller gjorde- form. Så, webViewDidStartLoad:(første parameteren er nettvisning) i stedet for loadStarted(tar ingen parametre) for eksempel.
I stedet for å sjekke om en delegat reagerer på en velger hver gang vi vil melding det, kan du cache at informasjonen når delegatene er satt. En svært ren måte å gjøre dette på er å bruke en bitfield, som følger:
@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
Så, i kroppen, kan vi sjekke at vår representant håndterer meldinger ved å gå vår delegateRespondsTostruct, snarere enn ved å sende -respondsToSelector:om igjen og om igjen.
Før protokoller eksisterte, var det vanlig å bruke en kategori på NSObjectå erklære metodene delegat kunne gjennomføre. For eksempel, CALayergjør likevel dette:
@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end
Dette forteller egentlig det kompilator som ethvert objekt kan implementere displayLayer:.
Du vil da bruke samme -respondsToSelector:tilnærming som beskrevet ovenfor for å kalle denne metoden. Delegater bare implementere denne metoden, og tildele delegateeiendom, og det er det (det er ingen erklære deg i samsvar med en protokoll). Denne metoden er vanlig i Apples biblioteker, men nye koden bør bruke mer moderne protokollen tilnærming ovenfor, ettersom denne tilnærmingen forurenser NSObject(som gjør autofullfør mindre nyttig) og gjør det vanskelig for kompilatoren å advare deg om skrivefeil og lignende feil.
Den godkjente svaret er flott, men hvis du leter etter en ett minutt svaret prøv dette:
MyClass.h filen skal se slik ut (legg delegere linjer med kommentarer!)
#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 filen skal se slik ut
#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
Hvis du vil bruke delegat i en annen klasse (UIViewController kalt MyVC i dette tilfellet) 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
Implementere delegere metode
- (void) myClassDelegateMethod: (MyClass *) sender {
NSLog(@"Delegates are great!");
}
Ved bruk av formelle protokollen metode for å lage delegat støtte, har jeg funnet ut at du kan sikre riktig type kontroll (riktignok runtime, ikke kompilere tid) ved å legge noe sånt som:
if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
[NSException raise:@"MyDelegate Exception"
format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}
i delegat tilbehør (setDelegate) kode. Dette bidrar til å redusere feil.
Vær så snill! sjekk under enkel trinnvis tutorial for å forstå hvordan det fungerer delegater i iOS.
Jeg har skapt to ViewControllers (for sending av data fra en til en annen)
Kanskje dette er mer i retning av hva du mangler:
Hvis du kommer fra et C ++ som utsiktspunkt, delegatene tar litt tid å bli vant til - men i utgangspunktet 'de bare fungere'.
Måten det fungerer på er at du setter et objekt som du skrev som delegat til NSWindow, men objektet har bare implementeringer (metoder) for en eller noen få av de mange mulige delegere metoder. Så noe skjer, og NSWindowønsker å ringe til objekt - den bruker bare Objective-C er respondsToSelectormetoden for å finne ut om gjenstanden ønsker at metoden kalles, og deretter kaller det. Slik fungerer Objective-C - metoder er så opp på forespørsel.
Det er helt trivielt å gjøre dette med dine egne objekter, er det ikke noe spesielt skjer, kan du for eksempel har en NSArrayav 27 objekter, alle forskjellige typer objekter, bare 18 noen av dem har metoden -(void)setToBue;Den andre ni ikke. Så for å ringe setToBluepå alle 18 som trenger det gjort, noe som dette:
for (id anObject in myArray)
{
if ([anObject respondsToSelector:@selector(@"setToBlue")])
[anObject setToBlue];
}
Den andre tingen om delegatene er at de ikke blir beholdt, slik at du alltid må sette delegat til nili MyClass deallocmetoden.
Som en god praksis anbefalt av Apple, er det godt for representanten (som er en protokoll, per definisjon), for å samsvare med NSObjectprotokollen.
@protocol MyDelegate <NSObject>
...
@end
Og for å skape ekstra metoder innen representanten (dvs. metoder som trenger ikke nødvendigvis bli implementert), kan du bruke den @optionalmerknaden som dette:
@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
Så når du bruker metoder som du har angitt som ekstrautstyr, må du (i klassen) sjekke med respondsToSelectorom visningen (som er i samsvar med din representant) har faktisk gjennomført din valgfrie metoden (e) eller ikke.
Jeg tror alle disse svarene gjør mye fornuftig når du forstår delegater. Personlig kom jeg fra landet C / C ++ og før det prosessuelle språk som Fortran etc så her er mine 2 min tar på å finne lignende analoger i C ++ paradigme.
Hvis jeg skulle forklare delegater til en C ++ / Java programmerer vil jeg si
Hva er delegater? Dette er statiske pekere til klasser innen en annen klasse. Når du tildeler en peker, kan du ringe funksjoner / metoder i den klassen. Derfor vil noen av funksjonene klassen er "delegert" (I C ++ verden - peker til av en klasse objektet pekeren) til en annen klasse.
Hva er protokoller? Konseptuelt det fungerer som lignende formål som til topptekstfilen av klassen du tilordner som delegat klasse. En protokoll er en eksplisitt måte å definere hvilke metoder som må gjennomføres i klassen som er pekeren ble satt som en delegat i en klasse.
Hvordan kan jeg gjøre noe lignende i C ++? Hvis du har prøvd å gjøre dette i C ++, vil du ved å definere pekere til klasser (objekter) i klassen definisjon og deretter ledningsnett dem opp mot andre klasser som vil gi ekstra funksjoner som delegater til din base klasse. Men dette ledninger må maitained i koden, og vil være klønete og feiling utsatt. Objective C bare forutsetter at programmerere er ikke best på å opprettholde dette decipline og gir kompilatoren restriksjoner for å håndheve en ren gjennomføring.
En representant er bare en klasse som gjør en del arbeid for en annen klasse. Les følgende kode for en noe dumt (men forhåpentligvis opplysende) Lekeplass eksempel som viser hvordan dette gjøres i 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!"
}
I praksis blir delegater ofte brukes i følgende situasjoner
Klassene trenger ikke å vite noe om hverandre på forhånd, bortsett fra at representanten klassen er i samsvar med ønsket protokoll.
Jeg anbefaler å lese følgende to artikler. De hjalp meg å forstå delegater enda bedre enn den dokumentasjonen gjorde.
kan si at du har en klasse som du utviklet og ønsker å erklære en delegat egenskapen for å være i stand til å varsle det når en hendelse skjer:
@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
så du erklære en protokoll i MyClassheader-fil (eller en egen header-fil), og erklærer de nødvendige / Valgfritt hendelseshåndterere at representanten må / bør iverksette, da erklærer en eiendom i MyClassav type ( id< MyClassDelegate>) som betyr at alle mål c klasse som er tilpasset protokollen MyClassDelegate, vil du legge merke til at representanten eiendommen er erklært som svak, dette er svært viktig for å forebygge beholde syklus (oftest representanten beholder MyClasseksempel så hvis du erklærte representanten som beholder, begge vil beholde hverandre og heller ikke av dem vil noen gang bli utgitt).
du vil legge merke til også at protokollen metoder passerer MyClassforekomsten til representanten som parameter, dette er beste praksis i tilfelle representanten ønsker å ringe noen metoder på MyClassforekomst og også hjelper når representanten erklærer seg selv som MyClassDelegatetil flere MyClasstilfeller, som når du har flere UITableView'sforekomster i din ViewControllerog erklærer seg selv som en UITableViewDelegatetil dem alle.
og inni MyClassdeg varsle delegat med erklært hendelser som følger:
if([_delegate respondsToSelector:@selector(myClass: requiredEventHandlerWithParameter:)])
{
[_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}
du først sjekke om din delegat svarer til protokollen metoden som du er i ferd med å ringe i tilfelle representanten ikke gjennomføre det, og applikasjonen vil krasje da (selv om det kreves protokollen metoden).
Ok, dette er egentlig ikke et svar på spørsmålet, men hvis du ser opp hvordan du lager din egen delegat kanskje noe langt enklere kunne være en bedre løsning for deg.
Jeg neppe gjennomføre mine delegater fordi jeg sjelden trenger. Jeg kan bare ha én representant for en delegat objekt. Så hvis du vil representanten for enveis kommunikasjon / passerer data enn du er mye bedre av med meldinger.
NSNotification kan passere gjenstander til mer enn én mottaker, og det er svært enkelt å bruke. Det fungerer slik:
MyClass.m filen skal se slik ut
#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
For å bruke varsling på en annen klasser: Legg klasse som observatør:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherClassUpdatedItsData:) name:@"myClassUpdatedData" object:nil];
Implementere velgeren:
- (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
}
Ikke glem å fjerne klassen som observatør om
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Her er en enkel metode for å lage delegater
Lag protokollen i .h fil. Kontroller at er definert før protokollen med @class etterfulgt av navnet på UIViewController< As the protocol I am going to use is UIViewController class>.
Trinn 1: Lag en ny klasse protokoll kalt "YourViewController", som vil være den underklasse av UIViewController klasse og tildele denne klassen til den andre ViewController.
Trinn 2: Gå til "YourViewController" filen og endre det som følger:
#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
Metodene som definert i protokollen oppførsel kan kontrolleres med @optional og @required som en del av protokollen definisjonen.
Trinn 3: Gjennomføring av delegat
#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
// test om metoden er definert før du kaller det
- (void) someMethodToCallDelegate {
if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
[self.delegate delegateMethodName:self];
}
}
For å lage din egen delegat, først må du opprette en protokoll og erklære de nødvendige metoder, uten å implementere. Og deretter implementere denne protokollen i din header klasse hvor du ønsker å implementere representanten eller delegere metoder.
En protokoll som må deklareres som følger:
@protocol ServiceResponceDelegate <NSObject>
- (void) serviceDidFailWithRequestType:(NSString*)error;
- (void) serviceDidFinishedSucessfully:(NSString*)success;
@end
Dette er tjenesten klasse der noen oppgave som bør gjøres. Den viser hvordan du definerer delegat og hvordan du setter representanten. I gjennomføringen klassen etter at oppgaven er fullført representantens metodene kalles.
@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
Dette er hovedvisningen klasse fra der tjenesten klassen kalles ved å sette delegat til seg selv. Og også protokollen er implementert i overskriften klassen.
@interface viewController: UIViewController <ServiceResponceDelegate>
{
ServiceClass* _service;
}
- (void) go;
@end
@implementation viewController
//
//some methods
//
- (void) go
{
_service = [[ServiceClass alloc] init];
[_service setDelegate:self];
[_service someTask];
}
Det er det, og ved å implementere delegere metodene i denne klassen, vil kontroll komme tilbake når operasjonen / oppgaven er ferdig.
Disclaimer: Dette er den Swiftversjonen av hvordan du oppretter en delegate.
Så, hva er delegater? ... i programvareutvikling, er det generelle gjenbrukbare løsningsarkitekturer som bidrar til å løse hyppigst forekommende problemer innenfor en gitt kontekst, disse “maler”, så å si, er best kjent som design patterns. Delegatene er et design mønster som gjør at en gjenstand for å sende meldinger til et annet objekt når en bestemt hendelse skjer. Forestille seg et objekt A ringer et objekt B til å utføre en handling. Når handlingen er fullført, skal objektet A vite at B har fullført oppgaven og iverksette nødvendige tiltak, kan dette oppnås ved hjelp av delegater!
For en bedre forklaring, skal jeg vise deg hvordan du oppretter en egendefinert delegat som sender data mellom klasser, med Swift i et enkelt program, starte med å laste ned eller kloning av denne starter prosjektet og kjøre den!
Du kan se en app med to klasser, ViewController Aog ViewController B. B har to visninger som på trykk endrer bakgrunnsfargen på ViewController, ingenting for komplisert rett? vel nå la oss tenke på en enkel måte å også endre bakgrunnsfargen i klasse A når utsikten på klasse B er avlyttet.
Problemet er at denne utsikten er en del av klasse B og har ingen anelse om klasse A, så vi må finne en måte å kommunisere mellom disse to klassene, og det er der delegasjon skinner. Jeg delt gjennomføringen inn i 6 trinn, slik at du kan bruke dette som en jukselapp når du trenger det.
Trinn 1: Se etter pragma mark trinn 1 i ClassBVC fil og legge dette
//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}
Det første trinnet er å opprette en protocol, i dette tilfellet, vil vi skape protokollen i klasse B, i protokollen kan du lage så mange funksjoner som du vil, basert på kravene i implementeringen. I dette tilfellet har vi bare en enkel funksjon som godtar en valgfri UIColorsom et argument. Er en god praksis å navngi protokoller legge til ordet delegatepå slutten av klassenavnet, i dette tilfellet, ClassBVCDelegate.
trinn 2: Se etter pragma mark trinn 2 i ClassVBCog legge dette
//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?
Her har vi bare lage en delegat eiendom for klassen, må denne egenskapen vedta protocoltype, og det skal være valgfritt. I tillegg bør du legge den svake søkeord før eiendommen for å unngå beholde sykluser og potensielle minnelekkasjer, hvis du ikke vet hva det betyr ikke bekymre deg for nå, bare husk å legge til dette søkeordet.
trinn 3: Se etter pragma mark trinn 3 inne i handleTap methodi ClassBVCog legge dette
//MARK: step 3 Add the delegate method call here.
delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)
En ting du bør vite, kjøre programmet og trykk på hvilken som helst visning, vil du ikke se noen ny atferd, og det er riktig, men det som jeg ønsker å påpeke er at app er det ikke krasjer når representanten kalles, og det er fordi vi lage den som en valgfri verdi og det er derfor det ikke vil krasje selv delegert ikke finnes ennå. La oss nå gå til ClassAVCfilen og gjøre det, delegeres.
Trinn 4: Se etter pragma mark trinn 4 inne i handleTap metode ClassAVCog legge denne siden til din klasse type som dette.
//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}
Nå ClassAVC vedtatt ClassBVCDelegateprotokollen, kan du se at kompilatoren er å gi deg en feilmelding som sier “Skriv 'ClassAVC ikke samsvarer med protokollen 'ClassBVCDelegate' og dette bare betyr at du ikke brukte metodene for protokollen ennå, forestille seg at når klasse A vedtar protokollen er som å signere en kontrakt med klasse B og denne kontrakten sier “Enhver klasse adoptere meg MÅ bruke mine fungerer!”
Quick Merk: Hvis du kommer fra en Objective-Cbakgrunn du sannsynligvis tenker at du også kan holde kjeft denne feilen gjør at metoden valgfritt, men for min overraskelse, og sannsynligvis din, Swiftspråket tillater ikke valgfritt protocols, hvis du ønsker å gjøre det du kan opprette en utvidelse for din protocoleller bruke @objc søkeord i protocolgjennomføringen.
Personlig, hvis jeg må lage en protokoll med ulike valgfrie metoder jeg foretrekker å dele det opp i annen protocols, på den måten jeg vil følge konseptet med å gi en enkelt ansvar for mine objekter, men det kan variere basert på spesifikke implementasjonen.
her er en god artikkel om valgfritt metoder.
Trinn 5: Se etter pragma merket trinn 5 på innsiden av forberede for naturlig overgang fremgangsmåte og legge denne
//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
}
Her er vi bare å lage en forekomst av ClassBVCog tildele sin delegat til selv, men det som er selv her? vel, er selv den ClassAVCsom har fått delegert!
trinn 6: Til slutt, se etter pragma trinn 6 i ClassAVCog la oss bruke funksjonene i protocol, begynner å skrive func changeBackgroundColor og du vil se at det er auto-fullføre det for deg. Du kan legge til implementering inni den, i dette eksempelet, vil vi bare endre bakgrunnsfarge, legg dette.
//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}
Nå kjører app!
Delegateser overalt, og du sannsynligvis bruke dem uten å legge merke til, hvis du oppretter en tableviewi det siste du brukte delegasjonen, mange klasser av UIKITverk rundt dem og mange andre frameworksogså, de løse disse hovedproblemene.
Gratulerer, du bare gjennomføre en tilpasset delegat, jeg vet at du sannsynligvis tenker, så mye trøbbel bare for dette? vel, delegering en svært viktig design mønster å forstå hvis du ønsker å bli en iOSutbygger, og alltid huske på at de har 1-1 forhold mellom stedene.
Du kan se den opprinnelige tutorial her
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;
Metode:
-(void)delegateMEthod: (ArgType) arg{
}
I mitt synspunkt skape egen klasse for at representanten metoden, og du kan bruke hvor du vil.
i min 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;
etter at in.m fil skape matrise med objekter,
- (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];
}
}
}];
}
Her er alle satt for Custom delegat class.after at du kan bruke denne representanten metode der du want.for eksempel ...
i min annen viewcontroller import etter at
skape handling for å ringe delegat metode som dette
- (IBAction)dropDownBtn1Action:(id)sender {
DropDownViewController *vehicleModelDropView = [[DropDownViewController alloc]init];
vehicleModelDropView.dropDownType = DDCITY;
vehicleModelDropView.delegate = self;
[self presentViewController:vehicleModelDropView animated:YES completion:nil];
}
etter at samtalen delegat metode som dette
- (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;
}
}
Svaret er faktisk svarte, men jeg vil gjerne gi deg en "cheat sheet" for å lage en delegat:
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
La oss starte med et eksempel, hvis vi kjøper et produkt på nettet, det går gjennom prosessen som frakt / levering håndtert av forskjellige teams.So om frakt blir fullført, bør frakt teamet varsle levering team og det bør være 1-1 kommunikasjon som kringkasting denne informasjonen ville være overhead for andre mennesker / leverandør ønsker kanskje å passere denne informasjonen til å kreves mennesker.
Så hvis vi tenker i form av vår app, kan en hendelse være en online bestilling og forskjellige lagene kan være flere visninger.
Her er kode vurdere ShippingView som Shipping lag og DeliveryView som levering team:
//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
//
}
}
//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. Implementere metoden i klassen .m - (void) didRemoveCellWithTag: (NSInteger) tag {NSLog @ ( "Tag% d", tag);
}
Delegere: - Lag
@protocol addToCartDelegate <NSObject>
-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;
@end
Send og kan tildele delegat til å vise du sender data
[self.delegate addToCartAction:itemsModel isAdded:YES];