Όταν πρόκειται για μοτίβα αρχιτεκτονικής iOS, το σχέδιο σχεδίασης Model-View-Controller (MVC) είναι ιδανικό για τη μακροζωία και τη συντήρηση της βάσης κώδικα μιας εφαρμογής. Επιτρέπει στα μαθήματα να επαναχρησιμοποιούνται ή να αντικαθίστανται εύκολα για να υποστηρίξουν διάφορες απαιτήσεις αποσυνδέοντας τις μεταξύ τους. Αυτό βοηθά στη μεγιστοποίηση των πλεονεκτημάτων του αντικειμενοστρεφούς προγραμματισμού (OOP).
Ενώ αυτή η αρχιτεκτονική εφαρμογών iOS λειτουργεί καλά σε μικροεπίπεδο (μεμονωμένες οθόνες / ενότητες μιας εφαρμογής), ενδέχεται να προσθέσετε παρόμοιες λειτουργίες σε πολλά μοντέλα καθώς μεγαλώνει η εφαρμογή σας. Σε περιπτώσεις όπως η δικτύωση, η μετακίνηση κοινής λογικής από τις τάξεις των μοντέλων σας και σε μαθήματα βοηθητικών μονάδων μπορεί να είναι μια καλύτερη προσέγγιση. Σε αυτό το σεμινάριο AFNetworking iOS, θα σας διδάξω πώς να ρυθμίσετε ένα κεντρικό αντικείμενο δικτύωσης, το οποίο, αποσυνδεδεμένο από στοιχεία MVC μικρο-επιπέδου, μπορεί να επαναχρησιμοποιηθεί σε όλη την εφαρμογή αποσυνδεδεμένης αρχιτεκτονικής.
κατασκευή ιστολογίου με angularjs
Η Apple έχει καταφέρει να αφαιρέσει πολλές από τις πολυπλοκότητες της διαχείρισης υλικού κινητού σε εύχρηστα SDK iOS, αλλά σε ορισμένες περιπτώσεις, όπως δικτύωση, Bluetooth, OpenGL και επεξεργασία πολυμέσων, οι τάξεις μπορεί να είναι δυσκίνητες λόγω του στόχου τους να διατηρήσουν τα ευέλικτα SDK. Ευτυχώς, οι πλούσιοι Προγραμματιστής iOS Η κοινότητα έχει δημιουργήσει πλαίσια υψηλού επιπέδου για να απλοποιήσει τις περισσότερες κοινές περιπτώσεις χρήσης σε μια προσπάθεια απλοποίησης του σχεδιασμού και της δομής της εφαρμογής. Ένας καλός προγραμματιστής, που χρησιμοποιεί τις βέλτιστες πρακτικές της αρχιτεκτονικής εφαρμογών ios, ξέρει ποια εργαλεία να χρησιμοποιήσει, γιατί να τα χρησιμοποιήσει και πότε είναι καλύτερο να γράψετε τα δικά σας εργαλεία και μαθήματα από το μηδέν.
Το AFNetworking είναι ένα εξαιρετικό παράδειγμα δικτύωσης και ένα από τα πιο συχνά χρησιμοποιούμενα πλαίσια ανοιχτού κώδικα, το οποίο απλοποιεί τις καθημερινές εργασίες ενός προγραμματιστή. Απλοποιεί τη δικτύωση RESTful API και δημιουργεί αρθρωτά μοτίβα αιτήσεων / απόκρισης με επιτυχία, πρόοδο και αποτυχία ολοκλήρωσης αποτυχιών. Αυτό εξαλείφει την ανάγκη για μεθόδους εκπροσώπων που εφαρμόζονται από προγραμματιστές και προσαρμοσμένες ρυθμίσεις αιτήματος / σύνδεσης και μπορεί να συμπεριληφθεί σε οποιαδήποτε τάξη πολύ γρήγορα.
Το AFNetworking είναι υπέροχο, αλλά η αρθρωτότητά του μπορεί επίσης να οδηγήσει στη χρήση του με κατακερματισμένους τρόπους. Οι κοινές αναποτελεσματικές υλοποιήσεις μπορεί να περιλαμβάνουν:
Πολλαπλά αιτήματα δικτύου χρησιμοποιώντας παρόμοιες μεθόδους και ιδιότητες σε έναν ελεγκτή προβολής
Σχεδόν πανομοιότυπα αιτήματα σε πολλούς ελεγκτές προβολής που οδηγούν σε κατανεμημένες κοινές μεταβλητές που μπορούν να ξεφύγουν από το συγχρονισμό
Αιτήματα δικτύου σε μια κλάση για δεδομένα που δεν σχετίζονται με αυτήν την κλάση
Για εφαρμογές με περιορισμένο αριθμό προβολών, λίγες κλήσεις API για εφαρμογή και για αυτές που δεν είναι πιθανό να αλλάζουν συχνά, αυτό μπορεί να μην προκαλεί μεγάλη ανησυχία. Ωστόσο, πιθανότατα σκέφτεστε μεγάλα και έχετε προγραμματίσει πολλά χρόνια ενημερώσεων. Εάν η περίπτωσή σας είναι η τελευταία, πιθανότατα θα πρέπει να χειριστείτε:
Έκδοση API για υποστήριξη πολλαπλών γενεών μιας εφαρμογής
Προσθήκη νέων παραμέτρων ή αλλαγών στις υπάρχουσες παραμέτρους με την πάροδο του χρόνου για την επέκταση της δυνατότητας
Υλοποίηση εντελώς νέων API
Εάν ο κώδικας δικτύωσης είναι διασκορπισμένος σε ολόκληρη τη βάση κώδικα, αυτό είναι τώρα ένας πιθανός εφιάλτης. Ας ελπίσουμε ότι έχετε ορίσει τουλάχιστον μερικές από τις παραμέτρους σας στατικά σε μια κοινή κεφαλίδα, αλλά ακόμα και τότε μπορείτε να αγγίξετε δώδεκα τάξεις για ακόμη και τις πιο μικρές αλλαγές.
Δημιουργήστε ένα μοναδικό δίκτυο για να συγκεντρώσετε τον χειρισμό αιτημάτων, απαντήσεων και των παραμέτρων τους.
Ένα αντικείμενο singleton παρέχει ένα παγκόσμιο σημείο πρόσβασης στους πόρους της κατηγορίας του. Τα Singletons χρησιμοποιούνται σε καταστάσεις όπου αυτό το μοναδικό σημείο ελέγχου είναι επιθυμητό, όπως με τάξεις που προσφέρουν κάποια γενική υπηρεσία ή πόρο. Μπορείτε να αποκτήσετε την καθολική παρουσία από μια τάξη singleton μέσω μιας εργοστασιακής μεθόδου. - μήλο
Έτσι, ένα singleton είναι μια τάξη στην οποία θα έχετε μόνο μία παρουσία σε μια εφαρμογή που υπάρχει για τη ζωή της εφαρμογής. Επιπλέον, επειδή γνωρίζουμε ότι υπάρχει μόνο μία παρουσία, είναι εύκολα προσβάσιμο από οποιαδήποτε άλλη τάξη που χρειάζεται να έχει πρόσβαση στις μεθόδους ή τις ιδιότητές της.
Αυτός είναι ο λόγος για τον οποίο πρέπει να χρησιμοποιήσουμε ένα μόνο για τη δικτύωση:
Αρχικοποιείται στατικά, οπότε, μόλις δημιουργηθεί, θα έχει τις ίδιες μεθόδους και ιδιότητες διαθέσιμες σε κάθε κλάση που προσπαθεί να αποκτήσει πρόσβαση σε αυτήν. Δεν υπάρχει πιθανότητα περίεργων προβλημάτων συγχρονισμού ή αιτήματος δεδομένων από λάθος παρουσία μιας τάξης.
Μπορείτε να περιορίσετε τις κλήσεις API για να παραμείνετε κάτω από ένα όριο τιμών (π.χ. όταν πρέπει να διατηρήσετε τα αιτήματά σας API κάτω από πέντε ανά δευτερόλεπτο).
Στατικές ιδιότητες όπως όνομα κεντρικού υπολογιστή, αριθμοί θύρας, τελικά σημεία, έκδοση API, τύπος συσκευής, μόνιμα αναγνωριστικά, μέγεθος οθόνης κ.λπ. μπορούν να συσχετιστούν, έτσι ώστε μια αλλαγή να επηρεάζει όλα τα αιτήματα δικτύου.
Οι κοινές ιδιότητες μπορούν να επαναχρησιμοποιηθούν μεταξύ πολλών αιτημάτων δικτύου.
Το αντικείμενο singleton δεν καταλαμβάνει τη μνήμη μέχρι να δημιουργηθεί. Αυτό μπορεί να είναι χρήσιμο για άτομα με πολύ συγκεκριμένες περιπτώσεις χρήσης που ενδέχεται να μην χρειάζονται ορισμένοι χρήστες, όπως ο χειρισμός μετάδοσης βίντεο σε ένα Chromecast εάν δεν διαθέτουν τη συσκευή.
Τα αιτήματα δικτύου μπορούν να αποσυνδεθούν πλήρως από προβολές και ελεγκτές, ώστε να μπορούν να συνεχιστούν ακόμη και μετά την καταστροφή των προβολών και των ελεγκτών.
Η καταγραφή δικτύου μπορεί να συγκεντρωθεί και να απλοποιηθεί.
Τα κοινά συμβάντα για αποτυχία όπως οι ειδοποιήσεις μπορούν να επαναχρησιμοποιηθούν για όλα τα αιτήματα.
Η κύρια δομή ενός τέτοιου singleton θα μπορούσε να επαναχρησιμοποιηθεί σε πολλά έργα με απλές αλλαγές στατικής ιδιοκτησίας ανώτατου επιπέδου.
Μερικοί λόγοι για να μην χρησιμοποιήσετε singletons:
Μπορούν να χρησιμοποιηθούν υπερβολικά για να παρέχουν πολλαπλές ευθύνες σε μία τάξη. Για παράδειγμα, οι μέθοδοι επεξεργασίας βίντεο θα μπορούσαν να αναμειχθούν με μεθόδους δικτύωσης ή μεθόδους κατάστασης χρήστη. Αυτό πιθανότατα θα ήταν κακή πρακτική σχεδιασμού και θα οδηγούσε σε δυσνόητο κώδικα. Αντ 'αυτού, θα πρέπει να δημιουργηθούν πολλαπλά άτομα με συγκεκριμένες ευθύνες.
Το Singletons δεν μπορεί να υποκατηγορηθεί.
Το Singletons μπορεί να κρύψει εξαρτήσεις και έτσι να γίνει λιγότερο αρθρωτό. Για παράδειγμα, εάν αφαιρεθεί ένα singleton και λείπει μια κλάση από την εισαγωγή που εισήγαγε το singleton, αυτό μπορεί να οδηγήσει σε μελλοντικά προβλήματα (ειδικά εάν υπάρχουν εξωτερικές εξαρτήσεις βιβλιοθήκης).
γιατί το json είναι καλύτερο από το xml
Μια τάξη μπορεί να τροποποιήσει κοινόχρηστες ιδιότητες σε μονότονα κατά τη διάρκεια μακρών λειτουργιών που δεν είναι αναμενόμενες σε άλλη τάξη. Χωρίς σωστή σκέψη, τα αποτελέσματα μπορεί να διαφέρουν.
Οι διαρροές μνήμης σε ένα singleton μπορούν να γίνουν ένα σημαντικό ζήτημα δεδομένου ότι το ίδιο το singleton δεν διαγράφεται ποτέ.
Ωστόσο, χρησιμοποιώντας τις βέλτιστες πρακτικές της αρχιτεκτονικής εφαρμογών iOS, αυτά τα αρνητικά μπορούν να μετριαστούν. Μερικές βέλτιστες πρακτικές περιλαμβάνουν:
Κάθε singleton πρέπει να αναλάβει μία ευθύνη.
Μην χρησιμοποιείτε μονάδες για να αποθηκεύσετε δεδομένα που θα αλλάξουν γρήγορα από πολλές κατηγορίες ή νήματα εάν χρειάζεστε υψηλή ακρίβεια.
Δημιουργήστε μονάδες για να ενεργοποιήσετε / απενεργοποιήσετε τις λειτουργίες βάσει των διαθέσιμων εξαρτήσεων.
Μην αποθηκεύετε μεγάλες ποσότητες δεδομένων σε ιδιότητες singleton, καθώς θα παραμείνουν για όλη τη διάρκεια της εφαρμογής σας (εκτός εάν διαχειρίζεται με μη αυτόματο τρόπο).
Αρχικά, ως προϋπόθεση, προσθέστε το AFNetworking στο έργο σας. Η απλούστερη προσέγγιση είναι μέσω Cocoapods και οι οδηγίες βρίσκονται σε αυτό Σελίδα GitHub .
Ενώ βρίσκεστε σε αυτό, προτείνω να προσθέσετε UIAlertController+Blocks
και MBProgressHUD
(και πάλι εύκολα προστίθεται με τα CocoaPods). Αυτά είναι σαφώς προαιρετικά, αλλά αυτό θα απλοποιήσει σημαντικά την πρόοδο και τις ειδοποιήσεις σε περίπτωση που θέλετε να τις εφαρμόσετε στο singleton στο παράθυρο AppDelegate.
Μία φορά AFNetworking
προστίθεται, ξεκινήστε με τη δημιουργία μιας νέας κλάσης αφής κακάο που ονομάζεται NetworkManager
ως υποκατηγορία του NSObject
. Προσθέστε μια μέθοδο τάξης για πρόσβαση στον διαχειριστή. Το NetworkManager.h
Το αρχείο πρέπει να μοιάζει με τον παρακάτω κώδικα:
#import #import “AFNetworking.h” @interface NetworkManager : NSObject + (id)sharedManager; @end
Στη συνέχεια, εφαρμόστε τις βασικές μεθόδους προετοιμασίας για το singleton και εισαγάγετε την κεφαλίδα AFNetworking. Η εφαρμογή της τάξης σας θα πρέπει να έχει την ακόλουθη μορφή (ΣΗΜΕΙΩΣΗ: Αυτό προϋποθέτει ότι χρησιμοποιείτε την αυτόματη μέτρηση αναφοράς):
#import 'NetworkManager.h' @interface NetworkManager() @end @implementation NetworkManager #pragma mark - #pragma mark Constructors static NetworkManager *sharedManager = nil; + (NetworkManager*)sharedManager { static dispatch_once_t once; dispatch_once(&once, ^ { sharedManager = [[NetworkManager alloc] init]; }); return sharedManager; } - (id)init { if ((self = [super init])) { } return self; } @end
Εξαιρετική! Τώρα μαγειρεύουμε και είμαστε έτοιμοι να προσθέσουμε ιδιότητες και μεθόδους. Ως μια γρήγορη δοκιμή για να καταλάβετε πώς να αποκτήσετε πρόσβαση σε ένα singleton, ας προσθέσουμε τα ακόλουθα στο NetworkManager.h
:
@property NSString *appID; - (void)test;
Και τα ακόλουθα στο NetworkManager.m
:
#define HOST @”http://www.apitesting.dev/” static const in port = 80; … @implementation NetworkManager … //Set an initial property to init: - (id)init { if ((self = [super init])) { self.appID = @”1”; } return self; } - (void)test { NSLog(@”Testing out the networking singleton for appID: %@, HOST: %@, and PORT: %d”, self.appID, HOST, port); }
Στη συνέχεια, στην κύρια μας ViewController.m
αρχείο (ή ό, τι έχετε), εισαγάγετε NetworkManager.h
και μετά σε viewDidLoad
Προσθήκη:
[[NetworkManager sharedManager] test];
Εκκινήστε την εφαρμογή και θα πρέπει να δείτε τα ακόλουθα στην έξοδο:
Testing our the networking singleton for appID: 1, HOST: http://www.apitesting.dev/, and PORT: 80
Εντάξει, οπότε πιθανότατα δεν θα συνδυάσετε #define
, static const και @property
όλα αρέσει ταυτόχρονα, αλλά απλά δείχνοντας για σαφήνεια τις επιλογές σας. Το 'static const' είναι μια καλύτερη δήλωση για την ασφάλεια τύπου αλλά #define
μπορεί να είναι χρήσιμο στη δημιουργία συμβολοσειρών δεδομένου ότι επιτρέπει τη χρήση μακροεντολών. Για ό, τι αξίζει, χρησιμοποιώ #define
για συντομία σε αυτό το σενάριο. Εκτός αν χρησιμοποιείτε δείκτες, δεν υπάρχει μεγάλη πρακτική διαφορά μεταξύ αυτών των προσεγγίσεων δήλωσης.
Τώρα που καταλαβαίνετε #defines
, σταθερές, ιδιότητες και μεθόδους, μπορούμε να τις καταργήσουμε και να προχωρήσουμε σε πιο σχετικά παραδείγματα.
Φανταστείτε μια εφαρμογή στην οποία ο χρήστης πρέπει να συνδεθεί για πρόσβαση σε οτιδήποτε. Κατά την κυκλοφορία της εφαρμογής, θα ελέγξουμε εάν έχουμε αποθηκεύσει ένα διακριτικό ελέγχου ταυτότητας και, εάν ναι, θα εκτελέσουμε ένα αίτημα GET στο API μας για να δούμε αν το διακριτικό έχει λήξει ή όχι.
Στο AppDelegate.m
, ας καταχωρήσουμε μια προεπιλογή για το διακριτικό μας:
+ (void)initialize { NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:@'', @'token', nil]; [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; }
Θα προσθέσουμε μια επιταγή ελέγχου στο NetworkManager και θα λάβουμε σχόλια σχετικά με την επιταγή μέσω μπλοκ ολοκλήρωσης. Μπορείτε να σχεδιάσετε αυτά τα μπλοκ ολοκλήρωσης όπως θέλετε. Σε αυτό το παράδειγμα, χρησιμοποιώ επιτυχία με τα δεδομένα αντικειμένου απόκρισης και αποτυχία με τη συμβολοσειρά απόκρισης σφάλματος και έναν κωδικό κατάστασης. Σημείωση: Η αποτυχία μπορεί προαιρετικά να παραλειφθεί εάν δεν έχει σημασία για την πλευρά λήψης, όπως αύξηση της τιμής στα αναλυτικά στοιχεία.
NetworkManager.h
Πάνω @interface
:
typedef void (^NetworkManagerSuccess)(id responseObject); typedef void (^NetworkManagerFailure)(NSString *failureReason, NSInteger statusCode);
Στο @ Interface:
@property (nonatomic, strong) AFHTTPSessionManager * networkingManager;
- (void)tokenCheckWithSuccess:(NetworkManagerSuccess)success failure:(NetworkManagerFailure)failure;
NetworkManager.m:
Ορίστε το BASE_URL μας:
#define ENABLE_SSL 1 #define HOST @'http://www.apitesting.dev/' #define PROTOCOL (ENABLE_SSL ? @'https://' : @'http://') #define PORT @'80' #define BASE_URL [NSString stringWithFormat:@'%@%@:%@', PROTOCOL, HOST, PORT]
Θα προσθέσουμε μερικές βοηθητικές μεθόδους για να απλοποιήσουμε τα πιστοποιημένα αιτήματα, καθώς και να αναλύσουμε σφάλματα (αυτό το παράδειγμα χρησιμοποιεί ένα διακριτικό ιστού JSON):
- (AFHTTPSessionManager*)getNetworkingManagerWithToken:(NSString*)token { if (self.networkingManager == nil) { self.networkingManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:BASE_URL]]; if (token != nil && [token length] > 0) { NSString *headerToken = [NSString stringWithFormat:@'%@ %@', @'JWT', token]; [self.networkingManager.requestSerializer setValue:headerToken forHTTPHeaderField:@'Authorization']; // Example - [networkingManager.requestSerializer setValue:@'application/json' forHTTPHeaderField:@'Content-Type']; } self.networkingManager.requestSerializer = [AFJSONRequestSerializer serializer]; self.networkingManager.responseSerializer.acceptableContentTypes = [self.networkingManager.responseSerializer.acceptableContentTypes setByAddingObjectsFromArray:@[@'text/html', @'application/json', @'text/json']]; self.networkingManager.securityPolicy = [self getSecurityPolicy]; } return self.networkingManager; } - (id)getSecurityPolicy { return [AFSecurityPolicy defaultPolicy]; /* Example - AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; [policy setAllowInvalidCertificates:YES]; [policy setValidatesDomainName:NO]; return policy; */ } - (NSString*)getError:(NSError*)error { if (error != nil) { NSData *errorData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]; NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData: errorData options:kNilOptions error:nil]; if (responseObject != nil && [responseObject isKindOfClass:[NSDictionary class]] && [responseObject objectForKey:@'message'] != nil && [[responseObject objectForKey:@'message'] length] > 0) { return [responseObject objectForKey:@'message']; } } return @'Server Error. Please try again later'; }
Εάν προσθέσατε το MBProgressHUD, μπορεί να χρησιμοποιηθεί εδώ:
#import 'MBProgressHUD.h' @interface NetworkManager() @property (nonatomic, strong) MBProgressHUD *progressHUD; @end … - (void)showProgressHUD { [self hideProgressHUD]; self.progressHUD = [MBProgressHUD showHUDAddedTo:[[UIApplication sharedApplication] delegate].window animated:YES]; [self.progressHUD removeFromSuperViewOnHide]; self.progressHUD.bezelView.color = [UIColor colorWithWhite:0.0 alpha:1.0]; self.progressHUD.contentColor = [UIColor whiteColor]; } - (void)hideProgressHUD { if (self.progressHUD != nil) { [self.progressHUD hideAnimated:YES]; [self.progressHUD removeFromSuperview]; self.progressHUD = nil; } }
Και το αίτημα ελέγχου διακριτικών:
- (void)tokenCheckWithSuccess:(NetworkManagerSuccess)success failure:(NetworkManagerFailure)failure { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *token = [defaults objectForKey:@'token']; if (token == nil || [token length] == 0) { if (failure != nil) { failure(@'Invalid Token', -1); } return; } [self showProgressHUD]; NSMutableDictionary *params = [NSMutableDictionary dictionary]; [[self getNetworkingManagerWithToken:token] GET:@'/checktoken' parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) { [self hideProgressHUD]; if (success != nil) { success(responseObject); } } failure:^(NSURLSessionTask *operation, NSError *error) { [self hideProgressHUD]; NSString *errorMessage = [self getError:error]; if (failure != nil) { failure(errorMessage, ((NSHTTPURLResponse*)operation.response).statusCode); } }]; }
Τώρα, στη μέθοδο ViewController.m viewWillAppear, θα ονομάσουμε αυτήν τη μέθοδο singleton. Παρατηρήστε την απλότητα του αιτήματος και τη μικρή εφαρμογή από την πλευρά του Ελεγκτή προβολής.
[[NetworkManager sharedManager] tokenCheckWithSuccess:^(id responseObject) { // Allow User Access and load content //[self loadContent]; } failure:^(NSString *failureReason, NSInteger statusCode) { // Logout user if logged in and deny access and show login view //[self showLoginView]; }];
Αυτό είναι! Παρατηρήστε πώς αυτό το απόσπασμα θα μπορούσε να χρησιμοποιηθεί σχεδόν σε οποιαδήποτε εφαρμογή που πρέπει να ελέγξει τον έλεγχο ταυτότητας κατά την εκκίνηση.
Ομοίως, μπορούμε να χειριστούμε ένα αίτημα POST για σύνδεση: NetworkManager.h:
- (void)authenticateWithEmail:(NSString*)email password:(NSString*)password success:(NetworkManagerSuccess)success failure:(NetworkManagerFailure)failure;
NetworkManager.m:
- (void)authenticateWithEmail:(NSString*)email password:(NSString*)password success:(NetworkManagerSuccess)success failure:(NetworkManagerFailure)failure { if (email != nil && [email length] > 0 && password != nil && [password length] > 0) { [self showProgressHUD]; NSMutableDictionary *params = [NSMutableDictionary dictionary]; [params setObject:email forKey:@'email']; [params setObject:password forKey:@'password']; [[self getNetworkingManagerWithToken:nil] POST:@'/authenticate' parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) { [self hideProgressHUD]; if (success != nil) { success(responseObject); } } failure:^(NSURLSessionTask *operation, NSError *error) { [self hideProgressHUD]; NSString *errorMessage = [self getError:error]; if (failure != nil) { failure(errorMessage, ((NSHTTPURLResponse*)operation.response).statusCode); } }]; } else { if (failure != nil) { failure(@'Email and Password Required', -1); } } }
Μπορούμε να φανταστούμε εδώ και να προσθέσουμε ειδοποιήσεις με το AlertController + Blocks στο παράθυρο AppDelegate ή απλά να στείλουμε αντικείμενα αποτυχίας πίσω στον ελεγκτή προβολής. Επιπλέον, θα μπορούσαμε να αποθηκεύσουμε τα διαπιστευτήρια χρήστη εδώ ή αντί να αφήσουμε το χειριστήριο προβολής να το χειριστεί. Συνήθως, εφαρμόζω ένα ξεχωριστό single UserManager που χειρίζεται διαπιστευτήρια και δικαιώματα που μπορούν να επικοινωνούν απευθείας με το NetworkManager (προσωπικές προτιμήσεις).
Για άλλη μια φορά, η πλευρά του ελεγκτή προβολής είναι εξαιρετικά απλή:
- (void)loginUser { NSString *email = @' [email protected] '; NSString *password = @'SomeSillyEasyPassword555'; [[NetworkManager sharedManager] authenticateWithEmail:email password:password success:^(id responseObject) { // Save User Credentials and show content } failure:^(NSString *failureReason, NSInteger statusCode) { // Explain to user why authentication failed }]; }
Ωχ! Ξεχάσαμε να εκδώσουμε το API και να στείλουμε τον τύπο της συσκευής. Επιπλέον, έχουμε ενημερώσει το τελικό σημείο από '/ checktoken' σε '/ token'. Από τη στιγμή που συγκεντρώσαμε τη δικτύωσή μας, αυτό είναι εξαιρετικά εύκολο να ενημερωθεί. Δεν χρειάζεται να ανακαλύψουμε τον κωδικό μας. Εφόσον θα χρησιμοποιήσουμε αυτές τις παραμέτρους σε όλα τα αιτήματα, θα δημιουργήσουμε ένα βοηθό.
μαθαίνουν γρήγορα ή αντικειμενικά γ
#define API_VERSION @'1.0' #define DEVICE_TYPE UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? @'tablet' : @'phone' - (NSMutableDictionary*)getBaseParams { NSMutableDictionary *baseParams = [NSMutableDictionary dictionary]; [baseParams setObject:@'version' forKey:API_VERSION]; [baseParams setObject:@'device_type' forKey:DEVICE_TYPE]; return baseParams; }
Οποιοσδήποτε αριθμός κοινών παραμέτρων μπορεί εύκολα να προστεθεί σε αυτό στο μέλλον. Στη συνέχεια, μπορούμε να ενημερώσουμε τις μεθόδους ελέγχου διακριτικών και ελέγχου ταυτότητας όπως:
… NSMutableDictionary *params = [self getBaseParams]; [[self getNetworkingManagerWithToken:token] GET:@'/checktoken' parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) { … … NSMutableDictionary *params = [self getBaseParams]; [params setObject:email forKey:@'email']; [params setObject:password forKey:@'password']; [[self getNetworkingManagerWithToken:nil] POST:@'/authenticate' parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) {
Θα σταματήσουμε εδώ, αλλά, όπως μπορείτε να δείτε, έχουμε συγκεντρώσει κοινές παραμέτρους και μεθόδους δικτύωσης σε έναν διαχειριστή singleton, ο οποίος απλοποίησε σημαντικά τις υλοποιήσεις του ελεγκτή προβολής. Οι μελλοντικές ενημερώσεις θα είναι απλές και γρήγορες και, το πιο σημαντικό, αποσυνδέει το δίκτυό μας από την εμπειρία του χρήστη. Την επόμενη φορά που η ομάδα σχεδιασμού θα ζητήσει μια αναθεώρηση UI / UX, θα ξέρουμε ότι η δουλειά μας έχει ήδη γίνει από την πλευρά της δικτύωσης!
Σε αυτό το άρθρο επικεντρωθήκαμε σε ένα μοναδικό δίκτυο, αλλά αυτές οι ίδιες αρχές θα μπορούσαν να εφαρμοστούν σε πολλές άλλες κεντρικές λειτουργίες όπως:
Εστιάσαμε επίσης σε μια αρχιτεκτονική εφαρμογών iOS, αλλά αυτό θα μπορούσε εξίσου εύκολα να επεκταθεί σε Android και ακόμη και σε JavaScript. Ως μπόνους, δημιουργώντας έναν πολύ καθορισμένο και προσανατολισμένο στη λειτουργία κώδικα, καθιστά τη μεταφορά εφαρμογών σε νέες πλατφόρμες μια πολύ πιο γρήγορη εργασία.
Συνοψίζοντας, αφιερώνοντας λίγο επιπλέον χρόνο στον αρχικό προγραμματισμό του έργου για τη δημιουργία βασικών μεμονωμένων μεθόδων, όπως το παραπάνω παράδειγμα δικτύωσης, ο μελλοντικός κώδικάς σας μπορεί να είναι καθαρότερος, απλούστερος και πιο διατηρήσιμος.
Το AFNetworking είναι μια βιβλιοθήκη δικτύωσης ανοιχτού κώδικα για iOS και macOS που απλοποιεί τις εργασίες ενός προγραμματιστή με ένα RESTful API δικτύωσης και δημιουργεί αρθρωτά μοτίβα αιτήσεων / απόκρισης με επιτυχία, πρόοδο και αποτυχία ολοκλήρωσης. Έχει μια πολύ ενεργή κοινότητα προγραμματιστών και χρησιμοποιείται σε μερικές από τις καλύτερες εφαρμογές.
Ένα αντικείμενο singleton είναι μια κλάση στην οποία θα έχετε μόνο μία παρουσία σε μια εφαρμογή που υπάρχει για τη ζωή της εφαρμογής. Επιπλέον, επειδή γνωρίζουμε ότι υπάρχει μόνο μία παρουσία, είναι εύκολα προσβάσιμο από οποιαδήποτε άλλη τάξη που χρειάζεται να έχει πρόσβαση στις μεθόδους ή τις ιδιότητές της.