Οποιοδήποτε εναντίον AnyObject στο Swift 3.0

Όταν αντιμετώπισα αυτά τα δύο ψευδώνυμα τύπου κατά την ανάλυση των δεδομένων JSON για πρώτη φορά, δεν είχα ιδέα πώς να τα διακρίνω ή να τα εφαρμόζω σωστά. Τι είναι λοιπόν; Οποιοσδήποτε και AnyObject είναι δύο ειδικοί τύποι στο Swift που χρησιμοποιούνται για εργασία με μη συγκεκριμένους τύπους.

Σύμφωνα με την τεκμηρίωση Swift της Apple,

  • Οποιοσδήποτε μπορεί να αντιπροσωπεύει μια παρουσία οποιουδήποτε τύπου καθόλου, συμπεριλαμβανομένων τύπων λειτουργιών και προαιρετικών τύπων.
  • Το AnyObject μπορεί να αντιπροσωπεύει μια εμφάνιση οποιουδήποτε τύπου κλάσης.

Εντάξει, αρκετά απλά - Οποιοδήποτε χρησιμοποιείται για όλους τους τύπους, το AnyObject χρησιμοποιείται για τύπους κλάσεων, σωστά;

Για να καταλάβω πώς συμπεριφέρονται πραγματικά στον κώδικα, αποφάσισα να παίξω μαζί τους σε μια Παιδική χαρά.

Οποιοδήποτε παράδειγμα

Οποιοσδήποτε μου επέτρεψε να δουλεύω με ένα συνδυασμό διαφορετικών τύπων, συμπεριλαμβανομένων λειτουργικών και μη κατηγοριών όπως Int, String και Bool. Σύμφωνα με την τεκμηρίωση, τα στοιχεία σε αυτήν τη συστοιχία είναι Structs που είναι τύποι αξίας, οπότε θεωρητικά το AnyObject δεν θα πρέπει να λειτουργεί σε αυτές τις περιπτώσεις.

Για να το επιβεβαιώσω αυτό, προσπάθησα να συμπεριλάβω τα Strings and Ints, τα οποία είναι τύποι αξίας στο Swift, χρησιμοποιώντας το AnyObject.

Σφάλμα AnyObjectArray όταν συμπεριλαμβάνονται τύποι Struct

Όπως ήταν αναμενόμενο, ο μεταγλωττιστής μου έδωσε ένα σφάλμα λέγοντας ότι τα στοιχεία δεν συμμορφώθηκαν με τον τύπο AnyObject στη συστοιχία. Γκότσα!

Τότε, αυτό το περίεργο πράγμα συνέβη όταν προσπάθησα να ακολουθήσω τις προτάσεις του μεταγλωττιστή:

Στοιχεία που έχουν χρωματίσει σε AnyObject

Τι συνέβη μόλις τώρα?! Πώς μπορώ να χρησιμοποιήσω το AnyObject σε Ints και Strings μεταφέροντας ξεκάθαρα κάθε στοιχείο στο AnyObject;

Τότε έγραψα το anyObjectArray στην κονσόλα.

Εκτύπωση anyObjectArray

Το στοιχείο Γεια προφανώς έμοιαζε σαν μια συμβολοσειρά για μένα, αλλά δεν είχε εισαγωγικά σαν μια κανονική τιμή String στο Swift!

Έπειτα, εκτύπωσα κάθε στοιχείο χρησιμοποιώντας έναν βρόχο in-in για να ελέγξω τον πραγματικό του τύπο και όχι τον τυποποιημένο τύπο του AnyObject.

Πρώτον, χρησιμοποίησα τον χειριστή για να δω αν τα στοιχεία είναι τύπου Swift Struct ή όχι.

Έλεγχος τύπων στοιχείων στο anyObjectArray 1

Είναι τύπου String! Τότε πώς θα μπορούσε να φτιαχτεί σε AnyObject; Και πάλι, οι Strings in Swift είναι Structs, όχι τύποι Class. Έτσι, θεωρητικά, δεν θα πρέπει να μπορώ να τους ρίξω ως AnyObject.

Τι?

Ήμουν τελείως μπερδεμένος και αποφάσισα να κάνω μερικά πειράματα μαζί του. Αυτή τη φορά χρησιμοποίησα τα NSNumber και NSString, τα οποία είναι τύποι αντικειμενικού τύπου C, για να ελέγξω τον τύπο κάθε στοιχείου.

Έλεγχος τύπων στοιχείων σε anyObjectArray 2

Περιμένετε, Γεια είναι επίσης ένα NSString και τα αριθμητικά στοιχεία είναι NSNumber! Και ... είναι τύποι αναφοράς στο Στόχο-Γ! Αυτός ήταν ο λόγος για τον οποίο το Hi δεν είχε εισαγωγικά στην κονσόλα; Έγραψα κάποιο άλλο κώδικα όπως παρακάτω για να δούμε αν η παραδοχή μου ήταν σωστή.

Εκτύπωση του πίνακα NSString και της σειράς στοιχειοσειρώνΓεια σας με Δεν υπάρχουν προσφορές στην κονσόλα ως NSString

Επιβεβαιωμένος! Τα στοιχεία που μετατρέπονται σε AnyObject στη συστοιχία είναι τώρα τύποι κλάσης του Objective-C: NSString και NSNumber.

Έτσι ... Τι συμβαίνει πραγματικά κάτω από την κουκούλα; Συνεχίσα να σκάβω αυτό το θέμα και βρήκα την πιο εύλογη απάντηση από το έγγραφο Χρήση Swift με κακάο και Objective-C (Swift 3.0.1).

Στο πλαίσιο της διαλειτουργικότητάς του με το Στόχο-Γ, η Swift προσφέρει βολικούς και αποτελεσματικούς τρόπους συνεργασίας με τα πλαίσια κακάο. Το Swift μετατρέπει αυτόματα ορισμένους τύπους αντικειμενικού τύπου C σε τύπους Swift και ορισμένους τύπους Swift σε τύπους αντικειμενικού τύπου C. Οι τύποι που μπορούν να μετατραπούν μεταξύ Objective-C και Swift αναφέρονται ως γεφυρωμένοι τύποι.
Οπουδήποτε μπορείτε να χρησιμοποιήσετε έναν γεφυρωμένο τύπο αναφοράς στόχου-C, μπορείτε να χρησιμοποιήσετε τον τύπο τιμής Swift. Αυτό σας επιτρέπει να επωφεληθείτε από τη λειτουργικότητα που είναι διαθέσιμη στην εφαρμογή του τύπου αναφοράς με τρόπο φυσικό στον κώδικα Swift. Για το λόγο αυτό, δεν πρέπει σχεδόν ποτέ να χρησιμοποιείτε έναν γεφυρωμένο τύπο αναφοράς απευθείας στον δικό σας κώδικα. Στην πραγματικότητα, όταν ο κώδικας Swift εισάγει API στόχου C, ο εισαγωγέας αντικαθιστά τους τύπους αναφοράς του στόχου C με τους αντίστοιχους τύπους τιμών. Ομοίως, όταν ο κώδικας του Στόχου-C εισάγει Swift API, ο εισαγωγέας αντικαθιστά τους τύπους Swift με τους αντίστοιχους τύπους αναφοράς του Στόχου-C. "

Με άλλα λόγια, ο μεταγλωττιστής κάνει ό, τι καλύτερο για να είναι ευέλικτος στο χειρισμό τέτοιων τύπων μέσω αυτόματης μετατροπής και γεφύρωσης, αποτρέποντας την εφαρμογή μας να καταρρέει εύκολα. Λαμπρός!

Όταν λοιπόν χρησιμοποιούμε το AnyObject; Όπως αναφέρεται στην τεκμηρίωση της Apple, το AnyObject μπορεί να χρησιμοποιηθεί για εργασία με αντικείμενα που προέρχονται από την κλάση αλλά δεν μοιράζονται μια κοινή κλάση ρίζας.

Αλλά είναι απολύτως απαραίτητο να το χρησιμοποιήσουμε στον κώδικα μας;

Η απάντησή μου στην ερώτηση είναι: Όχι.

Η Apple λέει:

Στο Swift 3, ο τύπος id στο Objective-C χαρτογραφείται τώρα στον Τύπο οποιουδήποτε από το Swift, ο οποίος περιγράφει μια τιμή οποιουδήποτε τύπου, είτε πρόκειται για κλάση, enum, struct είτε για οποιοδήποτε άλλο τύπο Swift. Αυτή η αλλαγή καθιστά τα API του Objective-C πιο ευέλικτα στο Swift, επειδή οι τύποι τιμών που ορίζονται από το Swift μπορούν να μεταβιβαστούν σε API του Objective-C και να εξαχθούν ως τύποι Swift, εξαλείφοντας την ανάγκη για χειροκίνητους τύπους "κουτιού".
Αυτά τα οφέλη επεκτείνονται επίσης στις συλλογές: οι τύποι συλλογής αντικειμένων-C NSArray, NSDictionary και NSSet, οι οποίοι προηγουμένως δέχονταν μόνο στοιχεία του AnyObject, μπορούν πλέον να περιέχουν στοιχεία οποιουδήποτε τύπου. Για τα περιεχόμενα των περιεχομένων, όπως το Λεξικό και το Σετ, υπάρχει ένας νέος τύπος AnyHashable που μπορεί να κρατήσει μια αξία οποιουδήποτε τύπου σύμφωνα με το πρωτόκολλο Swift Hashable.

Φαίνεται ότι ο μόνος από μόνος του λειτουργεί πολύ καλά στο γεφύρωμα αυτών των δύο γλωσσών στο Swift 3 χωρίς την ανάγκη χρήσης του AnyObject!

Ποιος ήταν λοιπόν ο τελικός συλλογισμός πίσω από αυτές τις αλλαγές;

Με τα δικά τους λόγια, η Apple εξηγεί:

Το Swift 3 διασυνδέεται με API του Objective-C με πιο ισχυρό τρόπο από τις προηγούμενες εκδόσεις. Για παράδειγμα, το Swift 2 χαρτογράφησε τον τύπο id στο Objective-C στον τύπο AnyObject στο Swift, το οποίο κανονικά μπορεί να κρατήσει μόνο τιμές των τύπων κλάσης. Το Swift 2 παρείχε επίσης σιωπηρές μετατροπές στο AnyObject για ορισμένους τύπους γεφυρωμένων τιμών, όπως String, Array, Λεξικό, Set και μερικούς αριθμούς, έτσι ώστε οι εγγενείς τύποι Swift να μπορούν να χρησιμοποιηθούν εύκολα με API Cocoa που αναμένουν NSString, NSArray, ή τις υπόλοιπες κατηγορίες δοχείων από το Ίδρυμα. Αυτές οι μετατροπές ήταν ασυμβίβαστες με την υπόλοιπη γλώσσα, καθιστώντας δύσκολη την κατανόηση του τι ακριβώς θα μπορούσε να χρησιμοποιηθεί ως AnyObject, με αποτέλεσμα σφάλματα.

Κάποιος θα επέμενε, ωστόσο, ότι εμείς οι προγραμματιστές του iOS πρέπει πάντα να είμαστε όσο το δυνατόν περισσότερο εξειδικευμένοι όσον αφορά τη χρήση τύπων σε κώδικα.

Πράγματι, η Apple συνιστά:

Χρησιμοποιήστε Οποιαδήποτε και AnyObject μόνο όταν χρειάζεστε ρητά τη συμπεριφορά και τις δυνατότητες που παρέχουν. Είναι πάντα καλύτερο να είστε συγκεκριμένοι για τους τύπους με τους οποίους αναμένετε να εργαστείτε στον κώδικα σας.

Σκεφτείτε το σενάριο αυτό: Δουλεύουμε με τον αριθμό 12.5 στο Swift. Σε αυτή την περίπτωση θα δηλώσαμε συγκεκριμένα ότι είναι ένας τύπος Double ή Float αντί να το δηλώνει τύπου Any. Με αυτόν τον τρόπο, μπορούμε να προσπελάσουμε εύκολα διάφορες ιδιότητες ή μεθόδους που είναι διαθέσιμες για τον συγκεκριμένο τύπο. Σε αυτό το πλαίσιο, θα χρησιμοποιούσαμε το AnyObject για τους τύπους κλάσεων, επειδή είναι λίγο πιο συγκεκριμένοι από οποιοδήποτε. Αλλά και πάλι, η χρήση του AnyObject είναι απλά μια επιλογή.

Ελπίζω ότι αυτή η ανάρτηση ιστολογίου βοήθησε πολλούς από τους φοβερούς προγραμματιστές εκεί έξω να αποσαφηνίσουν το Any and AnyObject. Χρησιμοποιήστε Οποιαδήποτε εμπιστοσύνη στο Swift 3 ενώ εργάζεστε με API που υποστηρίζονται από Objective-C.

Σας ευχαριστώ για την ανάγνωση και την ευτυχισμένη κωδικοποίηση!