2017-10-02 6 views
4

Lors de la mise à niveau vers Swift4 de Swift3, j'ai eu quelques problèmes liés à access control.Contrôle d'accès dans swift 4

Voici l'exemple de code. Ce qui était là Swift3, fonctionne bien dans les temps passés -

open class MyClass { 
    private let value: Int 
    static var defaultValue: Int { return 10 } 
    public init(value: Int = MyClass.defaultValue) { 
     self.value = value 
    } 
} 

Pour exécuter le code dans Swift4, je dois changer access control pour defaultValue-public. Voici la Swift4, la version compilation

open class MyClass { 
    private let value: Int 
    static public var defaultValue: Int { return 10 } 
    public init(value: Int = MyClass.defaultValue) { 
     self.value = value 
    } 
} 

Alors que je me demandais ce qui se passe, j'ai essayé de supprimer le contrôle d'accès open pour MyClass, il m'a permis de supprimer l'identificateur access pour defaultValue. Même peut le mettre à private. Je comprends tous les identifiants d'accès, mais je ne suis pas capable de comprendre ce comportement. Surtout le premier cas où xcode m'a forcé à changer access control de defaultValue à public.

Aidez-nous s'il vous plaît.

Répondre

4

Ce changement est dû au travail vers un modèle de résilience qui est déjà disponible via les attributs soulignés (@_inlineable, @_versioned, @_fixed_layout), mais elle doit encore être officiellement finalisé (donc vous ne devriez probablement pas utiliser ces soi-même les attributs encore). Vous pouvez lire sur le full proposed details of the resilience model here, ainsi que le Swift evolution discussion on it here.

En bref, une fonction inlineable est celui dont la mise en œuvre , ainsi que la déclaration, est exposée comme une partie de l'interface d'un module et peut donc être inline lorsqu'il est appelé à partir d'un autre module. Une fonction inlineable doit donc être accessible au public pour commencer (c'est-à-dire public ou plus).

Ce que vous recherchez est un changement qui fait default argument expressions for publically accessible functions inlineable, ce qui signifie qu'ils doivent être disponibles pour être évalués directement dans le binaire du module appelant. Cela réduit la surcharge d'appel d'une fonction avec des valeurs de paramètre par défaut d'un autre module, car le compilateur n'a plus besoin de faire un appel de fonction pour chaque argument par défaut; il connaît déjà la mise en œuvre.

Je ne crois pas que ce changement est officiellement documenté dans la sortie de Swift 4 lui-même, mais il est confirmé par l'ingénieur Swift compilateur Slava Pestov, who says:

diagnostic de résilience Swift 3.1 ajouté pour le code inlineable, Ce n'est pas une fonctionnalité officiellement supportée, mais dans Swift 4, nous avons également activé ces contrôles pour les expressions par défaut.

Donc, si vous avez une fonction accessible au public avec une expression d'argument par défaut (comme MyClass.defaultValue dans votre cas), cette expression peut se référer maintenant seulement à des choses qui font également partie de l'interface de ce module. Donc, vous devez rendre le defaultValue accessible au public.

Malheureusement, il n'existe actuellement aucun moyen de faire de la déclaration de la fonction private une partie de l'interface d'un module (ce qui vous permettrait de l'utiliser dans une expression d'argument par défaut). L'attribut qui faciliterait c'est @_versioned, mais il est interdit de (file)private pour les raisons suivantes given by Slava Pestov:

Ce serait un changement trivial pour permettre @_versioned sur private et fileprivate déclarations, mais il y a deux pièges à garder à l'esprit:

  • Les symboles privés sont mutilés avec un 'discriminateur' qui est fondamentalement un hachage du nom de fichier. Alors maintenant, il ferait partie de l'ABI, qui semble fragile - vous ne pouvez pas déplacer la fonction privée vers un autre fichier source , ou renommer le fichier source. De même, à l'heure actuelle, une fonction @_versioned devenant publique est une modification compatible ABI. Cela ne fonctionnerait plus si vous pouviez avoir des fonctions private @_versioned, car le nom du symbole changerait si devenait public.

Pour ces raisons, nous avons décidé de rejeter "private versioned" comme concept. Je me sens comme internal est assez ici.

Vous pourrait y parvenir avec un @_versioned var defaultValue si:

open class MyClass { 

    private let value: Int 

    @_versioned static var defaultValue: Int { 
     return 10 
    } 

    public init(value: Int = MyClass.defaultValue) { 
     self.value = value 
    } 
} 

La déclaration de MyClass.defaultValue est maintenant exportée en tant que partie de l'interface du module, mais ne peut toujours pas être appelé directement à partir du code d'un autre module (comme c'est internal). Cependant, le compilateur de ce module peut maintenant l'appeler lors de l'évaluation de l'expression d'argument par défaut. Mais, comme indiqué précédemment, vous ne devriez probablement pas utiliser un attribut souligné ici; vous devriez attendre que le modèle de résilience soit finalisé.

+0

Fascinant, capitaine! – matt