web-dev-qa-db-fra.com

"initialize" méthode de classe pour les classes dans Swift?

Je recherche un comportement similaire à la méthode de classe +(void)initialize d'Objective-C, en ce sens que la méthode est appelée une fois lors de l'initialisation de la classe et plus jamais par la suite.

Un simple class init () {} dans une class fermeture serait vraiment élégant! Et évidemment, lorsque nous utiliserons "class vars" au lieu de "static vars dans une fermeture de structure", tout se mariera très bien!

64
aleclarson

Si vous avez une classe Objective-C, il est plus simple de remplacer +initialize. Cependant, assurez-vous que sous-classes de votre classe annule également +initialize sinon le +initialize de votre classe peut être appelé plus d'une fois! Si vous le souhaitez, vous pouvez utiliser dispatch_once() (mentionné ci-dessous) pour vous protéger contre plusieurs appels.

class MyView : UIView {
  override class func initialize () {
    // Do stuff
  }
}

Si vous avez une classe Swift, le mieux que vous puissiez obtenir est dispatch_once() dans la déclaration init().

private var once = dispatch_once_t()

class MyObject {
  init () {
    dispatch_once(&once) {
      // Do stuff
    }
  }
}

Cette solution diffère de +initialize (qui est appelée la première fois qu'une classe Objective-C est envoyée par message) et n'est donc pas une réponse vraie à la question. Mais cela fonctionne assez bien, IMO.

60
aleclarson

Il n'y a pas de type initializer dans Swift.

«Contrairement aux propriétés d'instance stockées, vous devez toujours attribuer une valeur par défaut aux propriétés de type stockées. Cela est dû au fait que le type n'a pas d'initialiseur capable d'attribuer une valeur à une propriété de type stockée au moment de l'initialisation. ”

Extrait de: Apple Inc. «Le langage de programmation Swift.» iBooks


Vous pouvez utiliser une propriété de type} dont la valeur par défaut est une fermeture. Ainsi, le code dans la fermeture serait exécuté lorsque la propriété de type} _ (ou la variable de classe) est définie.

class FirstClass {
    class var someProperty = {
     // you can init the class member with anything you like or perform any code
        return SomeType
    }()
}

Mais class stored properties not yet supported (testé dans Xcode 8).

Une réponse consiste à utiliser static, c'est la même chose que class final.

Bon lien pour cela est

Définition d'une valeur de propriété par défaut avec une fermeture ou une fonction

Extrait de: Apple Inc. «Le langage de programmation Swift.» iBooks


Exemple de code:

class FirstClass {
    static let someProperty = {
        () -> [Bool] in
        var temporaryBoard = [Bool]()
        var isBlack = false
        for i in 1...8 {
            for j in 1...8 {
                temporaryBoard.append(isBlack)
                isBlack = !isBlack
            }
            isBlack = !isBlack
        }

        print("setting default property value with a closure")
        return temporaryBoard
    }()
}

print("start")
FirstClass.someProperty

Impressions

début

définition de la valeur de propriété par défaut avec une fermeture

Donc, il est évalué paresseux.

51
Binarian

Pour les classes @objc, class func initialize() fonctionne parfaitement, puisque +initialize est implémenté par le moteur d'exécution Objective-C. Mais pour les classes Swift "natives", vous devrez voir les autres réponses.

7
newacct

Vous pouvez utiliser les propriétés de type stockées à la place de la méthode initialize.

class SomeClass: {
  private static let initializer: Void = {
    //some initialization
  }()
}

Mais comme les propriétés des types stockés sont en fait initialisées paresseusement lors de leur premier accès, vous devrez les référencer quelque part. Vous pouvez le faire avec une propriété stockée ordinaire:

class SomeClass: {
  private static let initializer: Void = {
    //some initialization
  }()
  private let initializer: Void = SomeClass.initializer
}
2
Cy-4AH

@aleclarson l'a cloué, mais à partir de la récente édition de Swift 4, vous ne pouvez pas remplacer directement initialize. Vous pouvez toujours le réaliser avec Objective-C et les catégories pour les classes héritant de NSObject avec une méthode class/static swiftyInitialize, qui est appelée depuis Objective-C dans MyClass.m, que vous incluez dans les sources de compilation à côté de MyClass.Swift:

# MyView.Swift

import Foundation
public class MyView: UIView
{
    @objc public static func swiftyInitialize() {
        Swift.print("Rock 'n' roll!")
    }
}

# MyView.m

#import "MyProject-Swift.h"
@implementation MyView (private)
    + (void)initialize { [self swiftyInitialize]; }
@end

Si votre classe ne peut pas hériter de NSObject et que l'utilisation de +load au lieu de +initialize convient, vous pouvez procéder comme suit:

# MyClass.Swift

import Foundation
public class MyClass
{
    public static func load() {
        Swift.print("Rock 'n' roll!")
    }
}
public class MyClassObjC: NSObject
{
    @objc public static func swiftyLoad() {
        MyClass.load()
    }
}

# MyClass.m

#import "MyProject-Swift.h"
@implementation MyClassObjC (private)
    + (void)load { [self swiftyLoad]; }
@end

Il y a quelques pièges, en particulier lorsque vous utilisez cette approche dans des bibliothèques statiques, consultez le média complet post sur pour plus de détails! ✌️

1
Ian Bytchek