Bonjour, c'est dayossi des ingénieurs iOS.
Je veux offrir un service qui rend ma famille heureuse Nous avons publié une application de journal familial appelée HaloHalo.
Cette fois, à propos du traitement après une communication asynchrone J'ai écrit que le protocole était très pratique.
(Les livrables de cet article sont listés en bas)
«J'ai essayé de refléter la valeur dans CollectionView après avoir obtenu les données par communication asynchrone. D'une manière ou d'une autre, la méthode d'affichage ne fonctionne pas. "
Je pensais que c'était le déclencheur.
Cette fois, je me suis concentré sur le traitement de la communication asynchrone et je l'ai divisé en deux problèmes.
・ 1: Les données référencées sont incorrectes. ・ 2: la mise à jour de l'interface utilisateur est lente et ne peut pas être lissée
-Lorsque la valeur acquise par l'API est stockée dans le modèle de données construit avec le type de classe La valeur stockée est un type de référence. Même après l'avoir remplacé par une variable, si vous réécrivez les données dans la variable Les données originales seront également réécrites.
・ Ainsi, par exemple, vous pouvez obtenir plusieurs données utilisateur en même temps. Si vous souhaitez afficher des valeurs spécifiques à l'utilisateur Les données peuvent être réécrites avant la mise à jour de l'interface utilisateur, Il peut ne pas s'afficher comme prévu.
[Source de référence] Problèmes de type et solutions de contournement sans valeur sémantique
Comme le modèle MVC, la vue qui affiche l'interface utilisateur et le modèle qui contient les données nécessaires pour dessiner l'interface utilisateur sont en contact étroit. Lorsque tout le traitement est solidement écrit dans le contrôleur de vue et qu'il devient l'état du contrôleur de vue Fat Avec le processus d'acquisition des données du serveur via la communication API Parce que le processus de création de l'interface utilisateur se fait dans le même thread
Le traitement dans le thread principal a été arrêté, bien que ce soit peu de temps Le comportement de l'application s'arrêtera.
Par conséquent, je veux que l'interface utilisateur soit affichée de manière nette et élégante. Il y a un problème de blocage de l'écran.
[Source de référence] [Swift] Grand Central Dispatch (GCD) et Operation Queue Summary
Pour contrer ces problèmes, j'ai souvent pris personnellement les éléments suivants.
● Lorsque vous détenez des données, gérez-les avec le type valeur par struct
→ Si vous détenez les données JSON renvoyées par l'API en tant que type valeur par struct Parce que vous pouvez réduire considérablement le risque d'écrasement étrange lors de la réception de plusieurs résultats de communication.
● Gérez les données stockées en les plaçant dans une autre variable de type tableau ou dictionnaire
→ L'Arrey de Swift a une fonction pour conserver les données de type référence comme type valeur (... pratique !!!)
[Source de référence] Swift's Array était en fait incroyable)
● Insérer un traitement asynchrone à l'aide de DispatchQueue
→ Séparez le fil principal pour dessiner / mettre à jour l'interface utilisateur et le fil d'arrière-plan pour le traitement des données et la communication. Je voulais alléger le traitement du fil principal
[Source de référence] Exemple de traitement asynchrone de Swift (modèles multiples) [Swift] Grand Central Dispatch (GCD) et Operation Queue Summary
Cependant, comme moyen de communication pour refléter les données obtenues de manière asynchrone vers l'interface utilisateur Parce que j'écrivais un moyen de renvoyer la valeur avec un rappel
Le nid devenait de plus en plus profond et il était dans un état chaotique. .. .. Je ne veux pas le relire. .. .. Pleurs
class hoge{
/*
Par exemple, après avoir récupéré les données utilisateur du serveur
GetImage dans HugaClass()Avec la méthode
Je veux aller chercher les données d'image...
*/
//Instancier inutilement toute la classe...
let huga = HugaClass()
//Emboîtement profond et référence forte dans la fermeture...
func getUserData(){ (userData) in
let userId = userData.userId
huga.willFetchImage(userId){ (imageData) in
self.imageData.image = imageData.image
}
}
}
C'était le plus gros goulot d'étranglement "Comment mettre à jour l'interface utilisateur en fonction des données acquises?" C'était le point.
L'introduction est devenue longue, mais le sujet principal est enfin là.
Pour appeler le processus implémenté dans la classe Chaque fois que vous instanciez une classe et appelez un processus dans cette classe Il devient difficile de comprendre où et quel processus a été écrit.
Bien qu'il puisse être exporté avec un petit nombre de codes, Il y a aussi la fragilité que les scènes qui peuvent être utilisées sont très limitées.
Pendant ce temps, je lisais le modèle de conception de l'application iOS
Model
Je vais expliquer le modèle lui-même et l'implémentation du modèle comme RxSwift des points de vue suivants. ・ Faites-en un protocole et rendez-le faiblement couplé et testable ・ Retourner Observable pour améliorer l'installation avec VIew Model
(Source: Introduction aux modèles de conception d'applications iOS p124)
J'ai été impressionné par le contenu de "Protocolisation, couplage lâche et testable".
En bref, via protocole Nous reconnaissons que nous devons extraire et transmettre uniquement les informations dont nous avons besoin.
// MARK:-Il est clair quel type de traitement sera transféré!
protocol HugaProtocol{
func willFetchImage(_ userId:String)
}
class hoge: hugaProtocol{
//Peut être livré par protocole, pas par classe
private weak var repository:HugaProtocol?
init(repository:HugaProtocol){
self.repository = repository
}
func getUserData(){ (userData) in
let userId = userData.userId
input.willFetchImage(userId)
}
}
Cette façon d'écrire rend inutile de dépendre d'une classe spécifique.
Vous n'avez pas à vous soucier d'appeler un processus dans une classe particulière Toute classe conforme au protocole Vous pouvez rendre disponible le traitement dans le protocole.
En d'autres termes, vous aurez la possibilité de modifier la conception.
De plus, c'est mieux que la méthode conventionnelle de coller des classes ensemble par traitement de rappel. Vous pouvez clairement voir les responsabilités de chaque classe, donc Cela permet de mieux comprendre où et ce qui est traité.
La différence entre orienté protocole et orienté objet, et les avantages de l'orientation protocole J'ai finalement remarqué ici. .. ..
[Source de référence] J'ai étudié la programmation orientée protocole WWDC 2015 "Programmation orientée protocole avec Swift"
La caractéristique du protocole est Le fait est que vous pouvez appeler un processus spécifique sans dépendre d'une classe spécifique.
Ainsi, dans le cycle de vie de CollectionView et TableView Même si vous ne forcez pas l'acquisition de données → dessin de l'interface utilisateur → mise à jour de l'interface utilisateur dans le même thread
Après avoir acquis les données, enregistrez les données, puis appelez le processus de rechargement. Vous pouvez utiliser la méthode de mise à jour de l'interface utilisateur → redessiner l'interface utilisateur.
Prise en charge flexible du traitement asynchrone par conception et protocole d'application Et il semble que l'animation fluide de l'interface utilisateur ne sera pas gâchée.
C'est déjà un protocole génial ... j'ai été impressionné !!
Si vous pouvez utiliser le protocole, non seulement la conception sera facile à comprendre J'ai seulement le sentiment que cela peut être une application iOS qui résiste au changement. J'étais vraiment excité !!
Surtout pour les applications qui effectuent fréquemment des communications asynchrones Le protocole semble être très utile.
Je me ferai plus d'amis avec le protocole à partir de maintenant !!
(Ceci est juste un exemple d'utilisation de protocole. Veuillez pardonner le fait qu'il ne peut pas être utilisé dans la pratique tel quel) https://github.com/Kohei312/CollectioView_loose-coupling
Je voulais le lire plus tôt ... C'est facile à comprendre et je le recommande vraiment! Yoshitaka Seki, Shoshin Fumi, Kenji Tanaka et al. Introduction aux modèles de conception d'applications iOS (2018) PEAKS Publishing
Swift's Array était vraiment génial Type de valeur pure Swift Problèmes de type et solutions de contournement sans valeur sémantique
Exemple de traitement asynchrone de Swift (modèles multiples) [Swift] Grand Central Dispatch (GCD) et Operation Queue Summary
Qu'est-ce que la programmation orientée protocole Protocole Swift
[Swift] Développement iOS intégrant DDD Partie 1 ~ Cas d'utilisation et délégué ~ Modèle de notification entre Swift et objets [iOS] Comprenez fermement le délégué iOS Qu'est-ce que Delegate dans Swift et pourquoi l'utiliser [Swift] Flux de mise en œuvre du délégué
Dependency Injection(DI) Injection de dépendances: injection de dépendances Concevez avec Swift pour être facile à tester en utilisant le principe de l'inversion des dépendances
(+α) [Swift] Référence circulaire qui tend à créer une dépendance