Ξέρω πώς λειτουργούν οι αντιπρόσωποι, και ξέρω πώς μπορώ να τα χρησιμοποιούν.
Αλλά πώς μπορώ να δημιουργήσω;
Ξέρω πώς λειτουργούν οι αντιπρόσωποι, και ξέρω πώς μπορώ να τα χρησιμοποιούν.
Αλλά πώς μπορώ να δημιουργήσω;
Μια πληρεξούσιος 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(προ-ARC) για να αποφευχθεί διατηρούν βρόχους, δεδομένου ότι ο πληρεξούσιος ενός αντικειμένου συχνά κατέχει ισχυρή αναφορά σε αυτό το αντικείμενο. (Για παράδειγμα, ένας ελεγκτής άποψη είναι συχνά ο εκπρόσωπος μιας προβολής που περιέχει.)
Για να ορίσετε τη δική σας συνέδρους, θα πρέπει να δηλώνουν τις μεθόδους τους κάπου, όπως συζητήθηκε στην Έγγραφα της Apple για τα πρωτόκολλα . Μπορείτε συνήθως να δηλώσει ένα επίσημο πρωτόκολλο. Η δήλωση, παραφρασμένη από UIWebView.h, θα είναι κάπως έτσι:
@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end
Αυτό είναι ανάλογο με μία διεπαφή ή αφηρημένη κλάση βάσης, δεδομένου ότι δημιουργεί ένα ειδικό τύπο για εκπροσώπου σας, UIWebViewDelegateσε αυτή την περίπτωση. Εφαρμοστές Εκπρόσωπος θα πρέπει να εγκρίνει το πρωτόκολλο αυτό:
@interface MyClass <UIWebViewDelegate>
// ...
@end
Και στη συνέχεια να εφαρμόσουν τις μεθόδους στο πρωτόκολλο. Για τις μεθόδους που δηλώνονται στο πρωτόκολλο ως @optional(όπως και οι περισσότερες μέθοδοι εκπρόσωπος), θα πρέπει να ελέγξετε με -respondsToSelector:πριν από την κλήση μια συγκεκριμένη μέθοδο σε αυτό.
Οι μέθοδοι Εκπρόσωπος συνήθως το όνομα αρχίζει με το όνομα της κλάσης μεταβιβάζουσα, και να λάβει το αντικείμενο μεταβιβάζουσα ως πρώτη παράμετρο. Επίσης, χρησιμοποιούν συχνά ένα βού-, should-, ή did- μορφή. Έτσι, webViewDidStartLoad:(πρώτη παράμετρος είναι η προβολή ιστοσελίδων) και όχι loadStarted(λαμβάνοντας κανένα παραμέτρους) για παράδειγμα.
Αντί να ελέγξει αν ένας εκπρόσωπος ανταποκρίνεται σε έναν επιλογέα κάθε φορά που θέλουμε να το μήνυμα αυτό, μπορείτε να cache τις πληροφορίες αυτές όταν έχουν οριστεί εκπρόσωποι. Ένας πολύ καθαρό τρόπο για να γίνει αυτό είναι να χρησιμοποιήσετε ένα bitfield, ως εξής:
@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
Στη συνέχεια, στο σώμα, μπορούμε να ελέγξουμε ότι η εκπρόσωπος μας χειρίζεται τα μηνύματα από την πρόσβαση μας delegateRespondsTostruct, παρά με την αποστολή -respondsToSelector:ξανά και ξανά.
Πριν υπήρχαν πρωτόκολλα, ήταν σύνηθες να χρησιμοποιήσετε μια κατηγορία για NSObjectνα δηλώσει τις μεθόδους εκπρόσωπος θα μπορούσαν να εφαρμόσουν. Για παράδειγμα, CALayerεξακολουθεί να το κάνει αυτό:
@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end
Αυτό λέει ουσιαστικά ο compiler που οποιοδήποτε αντικείμενο θα μπορούσε να εφαρμόσει displayLayer:.
Στη συνέχεια, θα χρησιμοποιήσει την ίδια -respondsToSelector:προσέγγιση όπως περιγράφεται παραπάνω για να καλέσετε τη μέθοδο αυτή. Οι εκπρόσωποι απλά εφαρμόζουν αυτή τη μέθοδο και να εκχωρήσετε την delegateιδιότητα, και αυτό είναι όλο (δεν υπάρχει δήλωση που συμμορφώνονται με ένα πρωτόκολλο). Η μέθοδος αυτή είναι κοινή σε βιβλιοθήκες της Apple, αλλά νέος κώδικας θα πρέπει να χρησιμοποιούν την πιο σύγχρονη προσέγγιση πρωτόκολλο παραπάνω, δεδομένου ότι αυτή η προσέγγιση μολύνει NSObject(που κάνει αυτόματη συμπλήρωση λιγότερο χρήσιμο) και καθιστά δύσκολο για το compiler για να σας προειδοποιήσει για λάθη και παρόμοια λάθη.
Το εγκεκριμένο απάντηση είναι μεγάλη, αλλά αν ψάχνετε για μια απάντηση 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η μέθοδος για να καθορίσει εάν το αντικείμενό σας θέλει αυτή τη μέθοδο που ονομάζεται, και στη συνέχεια καλεί το. Αυτό είναι το πώς λειτουργεί στόχο-γ - Οι μέθοδοι σήκωσε το βλέμμα σε πρώτη ζήτηση.
Είναι εντελώς ασήμαντο για να το κάνετε αυτό με τη δική σας αντικείμενα, δεν υπάρχει τίποτα το ιδιαίτερο συμβαίνει, θα μπορούσε για παράδειγμα να έχει μία NSArrayαπό 27 αντικείμενα, όλα τα διαφορετικά είδη των αντικειμένων, μόνο το 18 μερικά από αυτά που έχουν την μέθοδο -(void)setToBue;Ο άλλος 9 δεν το κάνουν. Έτσι για να καλέσετε setToBlueσε όλες τις 18 που πρέπει να γίνει, κάτι σαν αυτό:
for (id anObject in myArray)
{
if ([anObject respondsToSelector:@selector(@"setToBlue")])
[anObject setToBlue];
}
Το άλλο πράγμα για συνέδρους είναι ότι δεν διατηρούνται, έτσι πρέπει πάντα να ρυθμίσετε το πληρεξούσιο για να nilσου στην MyClass deallocμέθοδο.
Σας παρακαλούμε! ελέγξτε παρακάτω απλό βήμα προς βήμα φροντιστήριο για να καταλάβουν πώς λειτουργεί αντιπρόσωποι στο iOS.
Έχω δημιουργήσει δύο ViewControllers (για την αποστολή δεδομένων από το ένα στο άλλο)
Ως καλή πρακτική που συνιστάται από την 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εάν η άποψη (που σύμφωνα με εκπρόσωπο σας) έχει πραγματικά εφαρμοστεί προαιρετική μέθοδο (ες) ή όχι.
Νομίζω ότι όλα αυτά απαντήσεις κάνει πολύ νόημα τη στιγμή που θα καταλάβετε συνέδρους. Προσωπικά, ήρθε από τη γη της C / C ++ και πριν ότι οι διαδικαστικές γλώσσες όπως η Fortran κλπ τόσο εδώ είναι 2 λεπτά μου να λάβει για την εξεύρεση παρόμοιων ανάλογα με C ++ παράδειγμα.
Αν ήθελα να εξηγήσω αντιπροσώπους σε C ++ / Java προγραμματιστής θα έλεγα
Τι είναι οι αντιπρόσωποι; Αυτά είναι στατική δείκτες σε κατηγορίες μέσα σε μια άλλη κατηγορία. Μόλις ορίσετε ένα δείκτη, μπορείτε να καλέσετε λειτουργίες / μέθοδοι στην εν λόγω κατηγορία. Ως εκ τούτου, ορισμένες λειτουργίες της τάξης σας είναι «κατ 'εξουσιοδότηση» (Στη C ++ κόσμο - δείκτη για να με δείκτη κλάση αντικειμένων) σε άλλη κατηγορία.
Τι είναι τα πρωτόκολλα; Εννοιολογικά χρησιμεύει ως παρόμοιο σκοπό, όπως στο αρχείο επικεφαλίδα της κατηγορίας που εκχώρηση ως τάξη εκπρόσωπος. Ένα πρωτόκολλο είναι μια ρητή τρόπο που ορίζουν τι πρέπει να εφαρμοστεί στην τάξη που είναι δείκτης ορίστηκε ως εκπρόσωπος μιας κατηγορίας μεθόδων.
Πώς μπορώ να κάνω κάτι παρόμοιο σε C ++; Αν προσπαθήσει να το κάνει αυτό σε C ++, θα καθορίζοντας δείκτες σε κατηγορίες (αντικείμενα) στον ορισμό της κατηγορίας και, στη συνέχεια, καλωδίωση τους επάνω σε άλλους κλάδους που θα παρέχουν πρόσθετες λειτουργίες, όπως οι αντιπρόσωποι για την βασική κλάση σας. Αλλά αυτή η καλωδίωση πρέπει να maitained μέσα στον κώδικα και θα είναι αδέξια και πιθανότητα σφάλματος. Στόχος Γ απλά υποθέτει ότι οι προγραμματιστές δεν είναι καλύτερα στη διατήρηση αυτής της decipline και παρέχει περιορισμούς compiler να επιβάλει μια καθαρή εφαρμογή.
Ένας εκπρόσωπος είναι απλά μια κατηγορία που κάνει κάποια εργασία για μια άλλη κατηγορία. Διαβάστε τον παρακάτω κώδικα για μια κάπως ανόητη (αλλά ελπίζω διαφωτιστικό) παράδειγμα χαρά που δείχνει πώς γίνεται αυτό το 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!"
}
Στην πράξη, οι αντιπρόσωποι που χρησιμοποιούνται συχνά στις ακόλουθες περιπτώσεις
Τα μαθήματα δεν χρειάζεται να γνωρίζουν τίποτα ο ένας για τον άλλο εκ των προτέρων εκτός από το ότι η τάξη εκπρόσωπος συμμορφώνεται με το απαιτούμενο πρωτόκολλο.
Συστήνω ιδιαίτερα διαβάζοντας τα ακόλουθα δύο άρθρα. Με βοήθησαν να καταλάβω αντιπρόσωποι ακόμα καλύτερα από ό, τι η τεκμηρίωση έκανε.
ας πούμε ότι έχετε μια τάξη που αναπτύχθηκε και θέλουν να δηλώσει ένα ακίνητο εκπρόσωπος να είναι σε θέση να ειδοποιεί όταν συμβεί κάποιο γεγονός:
@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αρχείο κεφαλίδας (ή ένα ξεχωριστό αρχείο header), και δηλώνει τα απαιτούμενα προαιρετικά χειριστές / event που εκπροσώπου σας πρέπει / θα πρέπει να εφαρμόζουν, στη συνέχεια, να δηλώσει ένα ακίνητο σε 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];
}
μπορείτε να ελέγξετε πρώτα αν εκπροσώπου σας ανταποκρίνεται με τη μέθοδο πρωτόκολλο που πρόκειται να καλέσετε σε περίπτωση που ο πληρεξούσιος δεν την εφαρμόσει και η εφαρμογή θα συντριβή στη συνέχεια (ακόμη και αν απαιτείται η μέθοδος πρωτόκολλο).
Εντάξει, αυτό δεν είναι πραγματικά μια απάντηση στο ερώτημα, αλλά αν ψάχνετε μέχρι το πώς να φτιάξετε το δικό σας αντιπρόσωπο ίσως κάτι πολύ πιο απλό θα μπορούσε να είναι μια καλύτερη απάντηση για εσάς.
Είμαι περίεργος να εφαρμόσουν οι αντιπρόσωποι μου, γιατί σπάνια χρειάζεται. Μπορώ να έχουν μόνο ένα πληρεξούσιο για ένα αντικείμενο εκπρόσωπος. Έτσι, εάν θέλετε πληρεξούσιος σας για έναν τρόπο επικοινωνίας / πέρασμα των δεδομένων από ό, τι είναι πολύ καλύτερη από τις κοινοποιήσεις.
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];
}
Εδώ είναι μια απλή μέθοδος για τη δημιουργία συνέδρους
Δημιουργία πρωτοκόλλου .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];
}
}
Για να δημιουργήσετε τις δικές σας αντιπρόσωπο, θα πρέπει πρώτα να δημιουργήσετε ένα πρωτόκολλο και να δηλώνουν τις απαραίτητες μεθόδους, χωρίς την εφαρμογή. Και στη συνέχεια να εφαρμόσουν το πρωτόκολλο αυτό στην κατηγορία κεφαλίδα σας όπου θέλετε να εφαρμόσουν τις μεθόδους εκπρόσωπο ή πληρεξούσιο.
Ένα πρωτόκολλο πρέπει να δηλώνονται ως εξής:
@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];
}
Αυτό είναι, και με την εφαρμογή μεθόδων εκπρόσωπος αυτής της κατηγορίας, ο έλεγχος θα επανέλθει όταν η επιχείρηση / εργασία γίνεται.
Αποποίηση: αυτή είναι η Swiftεκδοχή για το πώς να δημιουργήσετε ένα delegate.
Έτσι, ποιες είναι οι αντιπρόσωποι; ... στην ανάπτυξη λογισμικού, υπάρχουν γενικές αρχιτεκτονικές επαναχρησιμοποιήσιμων λύση που βοηθούν στην επίλυση των συχνά εμφανιζόμενων προβλημάτων σε ένα δεδομένο πλαίσιο, αυτά τα «πρότυπα», να το πω έτσι, είναι περισσότερο γνωστή ως σχεδιαστικά πρότυπα. Οι αντιπρόσωποι είναι ένα πρότυπο σχέδιο που επιτρέπει σε ένα αντικείμενο για να στείλετε μηνύματα σε ένα άλλο αντικείμενο, όταν συμβεί ένα συγκεκριμένο γεγονός. Φανταστείτε ένα αντικείμενο Α ζητά ένα αντικείμενο Β για να εκτελέσετε μια ενέργεια. Όταν η δράση είναι πλήρης, αντικείμενο Α θα πρέπει να γνωρίζουν ότι η Β έχει ολοκληρωθεί το έργο και να λάβει τα απαραίτητα μέτρα, αυτό μπορεί να επιτευχθεί με τη βοήθεια των αντιπροσώπων!
Για μια καλύτερη εξήγηση, εγώ είμαι πρόκειται να σας δείξει πώς να δημιουργήσετε μια προσαρμοσμένη εκπρόσωπο που περνά δεδομένων μεταξύ των τάξεων, με Swift με μια απλή αίτηση, ξεκινήστε με τη λήψη ή την κλωνοποίηση αυτού του έργου μίζα και να το εκτελέσετε!
Μπορείτε να δείτε μια εφαρμογή με δύο τάξεις, ViewController Aκαι ViewController B. Β έχει δύο απόψεις που στη βρύση αλλάζει το χρώμα του φόντου της ViewController, τίποτα δεν είναι πολύ περίπλοκο σωστά; και τώρα ας σκεφτούμε με έναν εύκολο τρόπο για να αλλάξει το χρώμα του φόντου της κατηγορίας Α, όταν οι απόψεις για την κατηγορία Β αξιοποιηθεί.
Το πρόβλημα είναι ότι αυτή η θέα είναι μέρος της κατηγορίας Β και δεν έχουν ιδέα για την κατηγορία Α, γι 'αυτό πρέπει να βρούμε έναν τρόπο να επικοινωνούν μεταξύ των δύο αυτών κατηγοριών, και αυτό είναι όπου αντιπροσωπεία λάμπει. Θα διαιρείται την εφαρμογή σε 6 βήματα ώστε να μπορείτε να χρησιμοποιήσετε αυτό ως ένα σκονάκι όταν το χρειάζεστε.
Βήμα 1: Ψάξτε για το βήμα σήματος pragma 1 στο αρχείο ClassBVC και να προσθέσετε αυτή
//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}
Το πρώτο βήμα είναι να δημιουργήσουμε μια protocol, σε αυτή την περίπτωση, θα δημιουργήσουμε το πρωτόκολλο της κατηγορίας Β, μέσα στο πρωτόκολλο, μπορείτε να δημιουργήσετε όσες λειτουργίες που θέλετε να σας με βάση τις απαιτήσεις της εφαρμογής σας. Σε αυτή την περίπτωση, έχουμε μόνο μια απλή συνάρτηση που δέχεται ένα προαιρετικό UIColorως επιχείρημα. Είναι μια καλή πρακτική να αναφέρουμε τα πρωτόκολλα σας προσθέτοντας τη λέξη delegateστο τέλος του το όνομα της κλάσης, σε αυτή την περίπτωση, ClassBVCDelegate.
Βήμα 2: Δείτε για το βήμα σήματος pragma 2 ClassVBCκαι προσθέστε αυτό
//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?
Εδώ απλά να δημιουργήσετε ένα ακίνητο εκπρόσωπο για την κατηγορία, αυτή η ιδιότητα πρέπει να υιοθετήσει τον protocolτύπο, και θα πρέπει να είναι προαιρετική. Επίσης, θα πρέπει να προσθέσετε το αδύναμο λέξη-κλειδί πριν από την περιουσία για την αποφυγή διατηρήσει κύκλους και τις πιθανές διαρροές μνήμης, αν δεν ξέρετε τι σημαίνει αυτό μην ανησυχείτε για τώρα, απλά να θυμάστε να προσθέσετε αυτή τη λέξη-κλειδί.
Βήμα 3: Ψάξτε για το βήμα σήματος pragma 3 μέσα στο handleTap methodτο ClassBVCκαι προσθέστε αυτό
//MARK: step 3 Add the delegate method call here.
delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)
Ένα πράγμα που πρέπει να ξέρετε, εκτελέστε την εφαρμογή και πατήστε εν πάση περιπτώσει, δεν θα δείτε καμία νέα συμπεριφορά και αυτό είναι σωστό, αλλά το πράγμα που θέλω να επισημάνω είναι ότι η εφαρμογή δεν είναι συντρίβεται όταν ο αντιπρόσωπος λέγεται, και είναι επειδή το δημιουργήσετε ως προαιρετική αξία και γι 'αυτό δεν θα συντριβή ακόμη και την κατ' εξουσιοδότηση δεν υπάρχει ακόμα. Ας πάμε τώρα στο ClassAVCαρχείο και να το κάνει, η κατ 'εξουσιοδότηση.
Βήμα 4: Ψάξτε για το βήμα σήματος pragma 4 στο εσωτερικό της μεθόδου handleTap το ClassAVCκαι προσθέστε αυτό δίπλα στον τύπο την τάξη σας αρέσει αυτό.
//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}
Τώρα ClassAVC ενέκρινε το ClassBVCDelegateπρωτόκολλο, μπορείτε να δείτε ότι compiler σας που σας δίνει ένα σφάλμα που λέει «Τύπος«ClassAVC δεν συμμορφώνεται με το πρωτόκολλο “ClassBVCDelegate” και αυτό σημαίνει μόνο ότι δεν χρησιμοποίησε τις μεθόδους του πρωτοκόλλου ακόμα, φανταστείτε ότι όταν κατηγορίας Α υιοθετεί το πρωτόκολλο είναι σαν την υπογραφή μιας σύμβασης με την κατηγορία Β και αυτή η σύμβαση λέει «Κάθε τάξη υιοθετώντας μου ΠΡΕΠΕΙ να χρησιμοποιήσετε τις λειτουργίες μου!»
Γρήγορη σημείωση: Αν έρχεστε από ένα Objective-Cφόντο που πιθανώς σκέφτεται ότι μπορείτε επίσης να κλείσει το σφάλμα κάνει η μέθοδος προαιρετική, αλλά και για μεγάλη μου έκπληξη, και ίσως η δική σας, Swiftτη γλώσσα δεν υποστηρίζει προαιρετικό protocols, αν θέλετε να το κάνετε, μπορείτε να δημιουργήσετε μια επέκταση για σας protocolή χρησιμοποιήστε το @objc λέξη-κλειδί σας protocolεφαρμογή.
Προσωπικά, Αν έχω να δημιουργήσετε ένα πρωτόκολλο με διαφορετικές εναλλακτικές μέθοδοι θα προτιμούσα να το σπάσει σε διαφορετικές protocols, με αυτόν τον τρόπο θα ακολουθήσουν την ιδέα να δοθεί μία ενιαία ευθύνη αντικείμενα μου, αλλά μπορεί να διαφέρουν ανάλογα με τη συγκεκριμένη εφαρμογή.
Εδώ είναι ένα καλό άρθρο σχετικά με εναλλακτικές μεθόδους.
Βήμα 5: Αναζητήστε το βήμα σήμα pragma 5 μέσα στο προετοιμαστούν για τη μέθοδο segue και να προσθέσετε αυτή
//MARK: step 5 create a reference of Class B and bind them through the `prepareforsegue` method.
if let nav = segue.destination as? UINavigationController, let classBVC = nav.topViewController as? ClassBVC {
classBVC.delegate = self
}
Εδώ είμαστε απλά δημιουργώντας μια παρουσία ClassBVCκαι να ορίσετε εκπρόσωπο της αυτοδιάθεσης, αλλά τι είναι αυτό εδώ; καλά, αυτο το ClassAVCοποίο έχει ανατεθεί!
Βήμα 6: Τέλος, αναζητήστε το βήμα pragma 6 ClassAVCκαι ας χρησιμοποιήσουμε τις λειτουργίες του protocol, αρχίστε να πληκτρολογείτε λει changeBackgroundColor και θα δείτε ότι είναι η αυτόματη συμπλήρωση για εσάς. Μπορείτε να προσθέσετε οποιοδήποτε εφαρμογή μέσα σε αυτό, σε αυτό το παράδειγμα, θα αλλάξουμε λίγο το χρώμα του φόντου, προσθέστε αυτό.
//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}
Τώρα τρέχει την εφαρμογή!
Delegatesείναι παντού και ίσως να τα χρησιμοποιήσετε χωρίς καν να παρατηρήσετε, αν δημιουργήσετε ένα tableviewστο παρελθόν έχετε χρησιμοποιήσει αντιπροσωπείας, πολλές κατηγορίες UIKITέργων γύρω από αυτά και πολλά άλλα frameworksεπίσης, να λύσει αυτά τα βασικά προβλήματα.
Συγχαρητήρια, μόλις εφαρμόσει μια προσαρμοσμένη εκπρόσωπο, ξέρω ότι είστε πιθανώς σκέψης, τόσο μεγάλο πρόβλημα ακριβώς γι 'αυτό; καλά, αντιπροσωπεία είναι ένα πολύ σημαντικό πρότυπο σχέδιο για να καταλάβετε εάν θέλετε να γίνετε iOSπρογραμματιστής, και πάντα να έχετε κατά νου ότι έχουν μία παρα ένα σχέση μεταξύ των αντικειμένων.
Μπορείτε να δείτε το πρωτότυπο φροντιστήριο εδώ
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{
}
Η απάντηση είναι πραγματικά απαντηθεί, αλλά θα ήθελα να σας δώσω ένα «σκονάκι» για τη δημιουργία ενός εκπροσώπου:
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
Ας ξεκινήσουμε με ένα παράδειγμα, αν αγοράσετε ένα προϊόν στο διαδίκτυο, περνά μέσα από τη διαδικασία, όπως ναυτιλία / παράδοση γίνεται από διαφορετικές teams.So εάν η ναυτιλία παίρνει ολοκληρωθεί, η ομάδα της ναυτιλίας θα πρέπει να ενημερώσει την ομάδα την παράδοση και θα πρέπει να είναι μία παρα ένα επικοινωνίας όπως μετάδοση αυτή η πληροφορία θα είναι γενικά για τους άλλους ανθρώπους / πωλητής μπορεί να θέλουν να περάσουν αυτές τις πληροφορίες μόνο για την απαιτούμενη ανθρώπους.
Έτσι, αν σκεφτούμε από την άποψη της εφαρμογής μας, ένα γεγονός μπορεί να είναι ένα online παραγγελία και διαφορετικές ομάδες μπορεί να είναι σαν πολλαπλές προβολές.
Εδώ είναι κώδικας θεωρούν 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
//
}
}
Κατά τη δική μου άποψη δημιουργούν ξεχωριστή κατηγορία για την εν λόγω μέθοδο εκπρόσωπο και μπορείτε να χρησιμοποιήσετε όπου θέλετε.
στην Προσαρμοσμένη DropDownClass.h μου
typedef enum
{
DDSTATE,
DDCITY
}DropDownType;
@protocol DropDownListDelegate <NSObject>
@required
- (void)dropDownDidSelectItemWithString:(NSString*)itemString DropDownType:(DropDownType)dropDownType;
@end
@interface DropDownViewController : UIViewController
{
BOOL isFiltered;
}
@property (nonatomic, assign) DropDownType dropDownType;
@property (weak) id <DropDownListDelegate> delegate;
@property (strong, nonatomic) NSMutableArray *array1DropDown;
@property (strong, nonatomic) NSMutableArray *array2DropDown;
μετά από αυτό το αρχείο in.m δημιουργήσει πίνακα με αντικείμενα,
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat rowHeight = 44.0f;
return rowHeight;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return isFiltered?[self.array1DropDown count]:[self.array2DropDown count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"TableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (self.delegate) {
if (self.dropDownType == DDCITY) {
cell.textLabel.text = [self.array1DropDown objectAtIndex:indexPath.row];
}
else if (self.dropDownType == DDSTATE) {
cell.textLabel.text = [self.array2DropDown objectAtIndex:indexPath.row];
}
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self dismissViewControllerAnimated:YES completion:^{
if(self.delegate){
if(self.dropDownType == DDCITY){
[self.delegate dropDownDidSelectItemWithString:[self.array1DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
}
else if (self.dropDownType == DDSTATE) {
[self.delegate dropDownDidSelectItemWithString:[self.array2DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
}
}
}];
}
Εδώ όλοι έχουν οριστεί για class.after Προσαρμοσμένη πληρεξούσιο που μπορείτε να χρησιμοποιήσετε αυτήν τη μέθοδο εκπρόσωπος όπου μπορείτε want.for παράδειγμα ...
κατά τη γνώμη μου μια άλλη εισαγωγή 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;
}
}
//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) ετικέτα {NSLog @ ( "Tag% d", tag)?
}
Μεταβιβάσει: - Δημιουργία
@protocol addToCartDelegate <NSObject>
-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;
@end
Αποστολή και παρακαλούμε να ορίσετε εκπρόσωπο για να δείτε στέλνετε δεδομένα
[self.delegate addToCartAction:itemsModel isAdded:YES];