[SWIFT] Amélioration du code difficile à lire avec du code lisible ~ Général

Bonjour, c'est Nekokichi ( @ nekokichi1_yos2 ).

Il s'agit de la 4e série d'amélioration du code lisible.

(Veuillez vous référer à ce qui suit pour plus d'informations) Amélioration du code difficile à lire avec du code lisible ~ Préparation [Amélioration du code difficile à lire avec un code lisible ~ Nom] (https://qiita.com/NEKOKICHI2/items/dc774bd79b1623032712) Amélioration du code difficile à lire avec un code lisible ~ Beauty Amélioration du code difficile à lire avec du code lisible ~ Commentaires

** Cette fois, nous améliorerons tout le code. ** **

Enseignement du code lisible

"Aligner les expressions conditionnelles" ・ Utilisez la forme affirmative pour les conditions ・ Rédigez d'abord des conditions faciles à comprendre

"L'opérateur ternaire n'a rien d'étonnant" ・ Le code peut être raccourci, mais il est difficile à lire.

"Fonction de retour précoce" ・ Préparez plusieurs sorties ・ Le code ne devient pas redondant

"La nidification est simple et simple" ・ Plus le nid est profond, le fardeau sur le lecteur ・ Il est nécessaire de toujours se souvenir des expressions conditionnelles et des variables, et il est nécessaire de se concentrer sur la compréhension de l'intérieur du nid.

"Variables explicatives, variables récapitulatives" -Variable explicative: indique la valeur du nom de la variable. ・ Variables récapitulatives: collectez d'énormes valeurs et expressions avec des variables

"Abus de l'évaluation des courts-circuits" ・ Moins de code n'est pas bon ・ Même si le contenu est le même, il est souhaitable qu'il soit facile à comprendre.

"Diviser une énorme expression" ・ Si la même expression apparaît plusieurs fois, utilisez une variable récapitulative -Avantages: phénomène de faute de frappe, code plus court, plus facile à corriger

"Supprimer la variable" -Dois-je utiliser des variables? Considérer ・ Pas besoin si vous pouvez facilement comprendre sans affecter de variables

"Réduisez la portée des variables" ・ La large portée rend difficile le suivi des modifications apportées. ・ Réduisez la portée du global au local -Utiliser des modificateurs d'accès (privé, public, statique)

"Abaisser la position de la définition" -Si vous le divisez en définition et traitement, vous devez toujours connaître la valeur de la variable. ・ Si vous définissez la définition et le traitement comme un ensemble, vous pouvez trouver les variables nécessaires et les rendre plus faciles à lire.

"Ecrire les variables une seule fois" ・ Si le nombre de modifications est important, la valeur actuelle ne sera pas connue. -Utiliser let ou privé pour interdire les changements permanents ・ Réduisez le nombre de changements dus aux variables explicatives, etc.

Divisez une énorme expression

Je convertis l'attributText de memoTextView en Data (), mais il est dangereux d'attribuer la valeur de l'interface utilisateur telle quelle, et le nom de la propriété est long, je le mets donc dans la variable inputAttrText dans l'instruction guardlet.

AddMemo.swift


let attributedMemoData = try! NSKeyedArchiver.archivedData(withRootObject: memoTextView.attributedText!, requiringSecureCoding: false)

AddMemo.swift


guard let inputAttrText = memoTextView.attributedText else { return }
let attributedMemoData = try! NSKeyedArchiver.archivedData(withRootObject: inputAttrText, requiringSecureCoding: false)

La valeur est affectée à la variable de destination de transition dans prepare ().

Je fais référence à la valeur rowth sélectionnée de memoTableView, mais comme le nom de propriété est trop long et difficile à voir, j'ai préparé une variable indexPathRow et raccourci la longueur de l'expression à attribuer.

ViewController.swift


let vc = segue.destination as! DisplayMemo
vc.selectedMemoObject   = memoListForRealm[memoTableView.indexPathForSelectedRow!.row]
vc.selectedMemoString   = memoList[memoTableView.indexPathForSelectedRow!.row]
vc.selectedIndexPathRow = memoTableView.indexPathForSelectedRow!.row

ViewController.swift


let vc = segue.destination as! DisplayMemo
guard let indexPathRow = memoTableView.indexPathForSelectedRow?.row else {
    return
}
vc.selectedMemoObject   = memoListForRealm[indexPathRow]
vc.selectedMemoString   = memoList[indexPathRow]
vc.selectedIndexPathRow = indexPathRow

Variables et lisibilité

Supprimer les variables inutiles

Attribuer une valeur à la propriété de la variable memoObject.

Cependant, j'ai attribué le inputAttrText converti en Data () à la variable attribuéMemoData, mais j'ai supprimé la variable attribuéMemoData car le passer directement peut réduire le code d'une phrase plutôt que de le passer à travers la variable.

AddMemo.swift


@IBAction func addMemo(_ sender: Any) {
    guard let inputAttrText = memoTextView.attributedText else { return }
    let memoObject             = MemoModel()
    // memoTextView.attributedText -> Data()
    let attributedMemoData     = try! NSKeyedArchiver.archivedData(withRootObject: inputAttrText, requiringSecureCoding: false)
    memoObject.data            = attributedMemoData
    memoObject.identifier      = String().randomString()

AddMemo.swift


@IBAction func addMemo(_ sender: Any) {
    guard let inputAttrText = memoTextView.attributedText else { return }
    let memoObject             = MemoModel()
    // memoTextView.attributedText -> Data()
    memoObject.data            = try! NSKeyedArchiver.archivedData(withRootObject: inputAttrText, requiringSecureCoding: false)
    memoObject.identifier      = String().randomString()

Lorsque vous faites glisser pour supprimer une cellule, vous supprimez les valeurs respectives du tableau utilisé pour Realm et tableView.

Cependant, Realm a supprimé les traitements inutiles car la modification est reflétée en manipulant la variable spécifiée dans Résultats <nom du modèle>.

ViewController.swift


func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
    let selectedMemo = memoListForRealm[indexPath.row]

    //Realm-Delete
    try! realm.write() {
        realm.delete(selectedMemo)
        realm.delete(memoListForRealm[indexPath.row])
    }

ViewController.swift


func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {

    //Realm-Delete
    try! realm.write() {
        realm.delete(memoListForRealm[indexPath.row])
    }

Réduire la portée des variables

private est un modificateur d'accès qui restreint les références (obtient) et les modifications (ensembles).

En donnant privé, vous pouvez l'empêcher d'être utilisé par d'autres fichiers et fonctions, et vous n'aurez pas à vous soucier des modifications et des références dans d'autres fichiers.

Aussi privé (Cette variable n'est pas utilisée dans d'autres fichiers) Peut être explicitement affiché, éliminant les tracas de suivi du code.

Donc, chaque fois que possible, j'ai ajouté privé à toutes les variables et fonctions.

Il n'est pas nécessaire d'ajouter private à @IBAction, mais s'il n'y a pas de modificateur, je pense qu'il sera exécuté quelque part, alors j'ai osé l'ajouter.

ViewController.swift


@IBOutlet weak var memoTableView: UITableView!

//Souvenirs à sauvegarder dans le royaume
var memoListForRealm:Results<MemoModel>!
// Realm
let realm               = try! Realm()
//Liste de mémos
var memoList            = [NSAttributedString]()

ViewController.swift


@IBOutlet private weak var memoTableView: UITableView!

//Souvenirs à sauvegarder dans le royaume
private var memoListForRealm:Results<MemoModel>!
// Realm
private let realm               = try! Realm()
//Liste de mémos
private var memoList            = [NSAttributedString]()

AddMemo.swift


let realm       = try! Realm()
let imagePicker = UIImagePickerController()

@IBAction func addMemo(_ sender: Any) {
    
@IBAction func attachImageGesture(_ sender: UILongPressGestureRecognizer) {

AddMemo.swift


private let realm       = try! Realm()
private let imagePicker = UIImagePickerController()

@IBAction private func addMemo(_ sender: Any) {

@IBAction private func attachImageGesture(_ sender: UILongPressGestureRecognizer) {

EditMemo.swift


@IBOutlet weak var memoTextView: UITextView!

// Realm
let realm                       = try! Realm()
let imagePicker                 = UIImagePickerController()

@IBAction func attachImageGesture(_ sender: UILongPressGestureRecognizer) {

@IBAction func updateMemo(_ sender: Any) {

EditMemo.swift


@IBOutlet private weak var memoTextView: UITextView!

// Realm
private let realm                       = try! Realm()
private let imagePicker                 = UIImagePickerController()

@IBAction private func attachImageGesture(_ sender: UILongPressGestureRecognizer) {

@IBAction private func updateMemo(_ sender: Any) {

DisplayMemo.swift


@IBOutlet weak var memoTextView: UITextView!

DisplayMemo.swift


@IBOutlet private weak var memoTextView: UITextView!

final est un modificateur qui limite l'héritage et les remplacements.

Indiquez explicitement que cette classe ne peut pas être héritée ou remplacée.

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
class AddMemo: UIViewController {
class DisplayMemo: UIViewController {
class EditMemo: UIViewController {

final class ViewController:UIViewController,UITableViewDelegate,UITableViewDataSource {
final class AddMemo: UIViewController {
final class EditMemo: UIViewController {
final class DisplayMemo: UIViewController {

Abaisser la position de la définition

Il est plus facile de voir si vous séparez la déclaration de variable de l'exécution de la fonction, mais si vous ne vous souvenez pas de l'existence de chaque variable, vous ne saurez pas l'ordre de traitement.

Par conséquent, en abaissant la position où la variable est définie, la variable requise est définie à proximité du traitement à exécuter, ce qui améliore la compréhension.

Dans le code ci-dessous, la définition des variables et le traitement des fonctions sont séparés car il existe de nombreux codes pour chacun.

Cependant, il existe de nombreuses variables définies, et il était difficile de comprendre le traitement ultérieur tout en se souvenant d'un seul coup.

Par conséquent, j'ai organisé les variables et les processus associés sous forme d'un ensemble.

ViewController.swift


func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    if let pickerImage = info[.originalImage] as? UIImage {
        //Paramètres requis pour la conversion en NSAttributedString
        let width                 = pickerImage.size.width
        let padding               = self.view.frame.width / 2
        let scaleRate             = width / (memoTextView.frame.size.width - padding)
        // 10%Image compressée vers
        let resizedImage          = pickerImage.resizeImage(withPercentage: 0.1)!
        let imageAttachment       = NSTextAttachment()
        var imageAttributedString = NSAttributedString()
        // memoTextView.attributedText -> NSMutableAttributedString
        let mutAttrMemoText       = NSMutableAttributedString(attributedString: memoTextView.attributedText)

        // resizedImage -> NSAttributedString()
        imageAttachment.image = UIImage(cgImage: resizedImage.cgImage!, scale: scaleRate, orientation: resizedImage.imageOrientation)
        imageAttributedString = NSAttributedString(attachment: imageAttachment)
        mutAttrMemoText.append(imageAttributedString)
        //Texte après l'ajout d'une image-> memoTextView.attributedText
        memoTextView.attributedText = mutAttrMemoText
    }
    dismiss(animated: true, completion: nil)
}

ViewController.swift


func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    if let pickerImage = info[.originalImage] as? UIImage {
        let width                 = pickerImage.size.width
        let padding               = self.view.frame.width / 2
        let scaleRate             = width / (memoTextView.frame.size.width - padding)
        // 10%Image compressée vers
        let resizedImage          = pickerImage.resizeImage(withPercentage: 0.1)!
        let imageAttachment       = NSTextAttachment()
        // resizedImage -> NSAttributedString()
        imageAttachment.image = UIImage(cgImage: resizedImage.cgImage!, scale: scaleRate, orientation: resizedImage.imageOrientation)

        var imageAttributedString = NSAttributedString()
        imageAttributedString = NSAttributedString(attachment: imageAttachment)

        // memoTextView.attributedText -> NSMutableAttributedString()
        let mutAttrMemoString     = NSMutableAttributedString(attributedString: memoTextView.attributedText)
        mutAttrMemoString.append(imageAttributedString)
        //Texte après l'ajout d'une image-> memoTextView.attributedText
        memoTextView.attributedText = mutAttrMemoString
    }
    dismiss(animated: true, completion: nil)
}

Un ensemble de définitions et d'implémentations pour deux UIAlertActions utilisées pour UIAlertController.

@IBAction private func attachImageGesture(_ sender: UILongPressGestureRecognizer) {
    let alert = UIAlertController(title: "Joindre une image", message: nil, preferredStyle: .actionSheet)

    let okAction = UIAlertAction(title: "OK", style: .default) { (action) in
        self.present(self.imagePicker, animated: true, completion: nil)
    }
    let cancelAction = UIAlertAction(title: "Annuler", style: .cancel, handler: nil)

    alert.addAction(okAction)
    alert.addAction(cancelAction)
    
    present(alert, animated: true, completion: nil)
}

@IBAction private func attachImageGesture(_ sender: UILongPressGestureRecognizer) {
    let alert = UIAlertController(title: "Joindre une image", message: nil, preferredStyle: .actionSheet)

    let okAction = UIAlertAction(title: "OK", style: .default) { (action) in
        self.present(self.imagePicker, animated: true, completion: nil)
    }
    alert.addAction(okAction)

    let cancelAction = UIAlertAction(title: "Annuler", style: .cancel, handler: nil)
    alert.addAction(cancelAction)
    
    present(alert, animated: true, completion: nil)
}

Sommaire

Jusqu'à présent, j'ai amélioré le code en me référant au code lisible, mais j'ai trouvé que ce livre est une voie royale pour apprendre le refactoring de base.

Il n'y a aucun moyen de réduire considérablement la quantité de code et d'écrire un beau code que tout le monde peut comprendre.

Simplement ・ Changer les noms des variables et des fonctions ・ Ajoutez des commentaires faciles à comprendre ・ Changer l'ordre de traitement C'était juste une méthode simple.

Cependant, refactoring = nettoyer le code n'est qu'un processus régulier.

Parce que c'est une méthode simple, je pense que c'est une méthode naturelle que vous ne devez jamais oublier.

Le contenu de ce livre est facile à lire dans le livre technique, mais il contient la méthode de refactoring qui est fidèle à l'essentiel.

Si vous souhaitez vivre en tant qu'ingénieur dans le futur, il est recommandé que vous appreniez la refactorisation à partir de ce livre.

Recommended Posts

Amélioration du code difficile à lire avec du code lisible ~ Général
Lombok avec VS Code
Gestion Docker avec VS Code
Formater Ruby avec VS Code
Bonjour tout le monde avec VS Code!
Réduisez le code redondant avec Lombok