Variables de classe non encore prises en charge

93

Je commence mon projet avec un contrôleur de vue fractionnée comme contrôleur de vue initial et le démarre automatiquement à partir du storyboard.

En règle générale, une application avec cette interface utilisateur a un et un seul contrôleur de vue fractionnée en tant que racine, donc je crée une variable statique dans la sous-classe et la définit lorsque l'initialisation a été effectuée.

Je veux donc essayer ce comportement avec rapidité.

J'ai lu le guide du langage de programmation Swift sur iBook à propos des propriétés de type (avec mot-clé statique et de classe) et j'ai essayé un morceau de code pour le travail:

import UIKit

class SplitViewController: UISplitViewController {

    class func sharedInstance() -> SplitViewController {
        return SplitViewController.instance
    }

    class let instance: SplitViewController = nil

    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        self.initialization()
    }

    init(coder aDecoder: NSCoder!) {
        super.init(coder: aDecoder);
        self.initialization()
    }

    func initialization() {
        SplitViewController.instance = self;
    }
}

mais j'ai compris quand Xcode a dit que le mot-clé de classe pour les propriétés de type n'était pas encore pris en charge.

détail de l'erreur dans l'image

Aviez-vous une solution pour cela?

Vincent Saluzzo
la source
Que se passe-t-il si vous remplacez «let» par «var»?
ZunTzu
Cela produit la même erreur.
Cezar
1
C'est la première graine, calmez-vous. :) Si le livre dit qu'il est pris en charge et qu'il n'est pas encore disponible, il le sera . Même l'erreur dit "encore" .
akashivskyy
1
Oui @akashivskyy vous avez raison mais peut-être que cela pourrait être et erreur de mon côté et quelqu'un a une solution pour faire ce comportement ...
Vincent Saluzzo
1
@lespommes Apple est notoirement discret sur tout ce qui est en suspens. C'est embarrassant pour eux qu'une fonctionnalité aussi standard et évidente manquait à leur énorme sortie de leur nouveau langage phare. De nombreuses améliorations sont nécessaires avant que Swift soit prêt pour une utilisation sérieuse.
Hyperbole

Réponses:

37

Swift prend désormais en charge les variables statiques dans les classes. Ce n'est pas exactement la même chose qu'une variable de classe (car elles ne sont pas héritées par des sous-classes), mais cela vous rapproche assez:

class X {
  static let y: Int = 4
  static var x: Int = 4
}

println(X.x)
println(X.y)

X.x = 5

println(X.x)
Facture
la source
1
Comme Bill le dit, ce n'est pas la même chose mais c'est dont j'ai besoin!
Vincent Saluzzo
@VincentSaluzzo, (et Bill) Quelle est la différence entre ceci et la variable de classe?
skywinder
La documentation Apple a récemment changé pour mettre à jour le statut: developer.apple.com/library/ios/documentation/Swift/Conceptual/... En fait, le classmot - clé ne peut être utilisé que pour les propriétés calculées maintenant et les statiques sont pour toutes les propriétés de type or struct)
Vincent Saluzzo
@skywinder Comme je l'ai mentionné dans ma réponse, les vraies variables de classe peuvent être héritées par des sous-classes. Les variables statiques ne peuvent pas.
Projet de loi
@VincentSaluzzo Apple met-il à jour son document? developer.apple.com/library/ios/documentation/Swift/Conceptual/… regardez le quatrième paragraphe: "Pour les types valeur (c'est-à-dire les structures et les énumérations), vous pouvez définir les propriétés de type stocké et calculé. Pour les classes, vous pouvez définir uniquement les propriétés du type calculé. "
fujianjin6471
73

L'incorporation d'une structure peut très bien fonctionner comme solution de contournement:

class SomeClass
{
  // class var classVariable: Int = 0
  // "Class variables not yet supported." Weird.

  // Workaround:
  private struct SubStruct { static var staticVariable: Int = 0 }

  class var workaroundClassVariable: Int
  {
    get { return SubStruct.staticVariable }
    set { SubStruct.staticVariable = newValue }
  }
}

La propriété de type calculé SomeClass.workaroundClassVariable peut ensuite être utilisée comme s'il s'agissait d'une propriété de type stocké.

Glessard
la source
1
Cela a fonctionné pour moi - sauf que j'ai dû abandonner le «public» car XCode 6.0 n'aimait pas que je déclare une classe publique dans une classe interne.
Ali Beadle
Fonctionne très bien, sauf que xcode n'autorise pas le type imbriqué dans un type générique ... donc si vous avez une classe générique, cela semble plutôt désespéré car seules les propriétés calculées sont possibles.
BenMQ
19

Il semble possible de déclarer des variables avec une durée de stockage statique dans la portée du fichier (comme en C):

var sharedInstance: SplitViewController? = nil

class SplitViewController: UISplitViewController {
    ....
    func initialization() {
        sharedInstance = self
    }
}
Nikolai Ruhe
la source
mmmh, pourquoi pas, mais définir un var à portée de fichier ne fait pas une fuite de mémoire dans une utilisation de longue date?
Vincent Saluzzo
@VincentSaluzzo Il n'y a aucune différence avec ce que vous faisiez avant Swift: stocker la seule instance dans une variable statique. Il n'y a rien à divulguer ici, sauf l'instance unique qui dure aussi longtemps que le processus.
Nikolai Ruhe
J'ai essayé cela dans la cour de récréation avec ma propre classe. Cela ne fonctionne pas parce que la classe n'a pas encore été déclarée lorsque vous avez initialisé cette var "statique". Je ne l'ai pas essayé dans le projet Xcode (je suppose que cela a dû fonctionner là-bas?). Il se peut donc que je doive trouver une "déclaration avant de classe" comme vous le faites toujours lorsque vous spécifiez le protocole d'une classe.
kawingkelvin
2
Notez que dans Xcode 6.0, vous ne pouvez pas avoir deux variables d'étendue de fichier avec le même nom, même si elles le sont private.
nschum
@NikolayTsenkov Exactement.
Nikolai Ruhe
14

Ma méthode préférée consiste simplement à utiliser une variable de portée de fichier privé en dehors de la classe, puis à implémenter des getters et des setters de classe / statique:

private var _classVar: Int = 0;

class SomeClass
{
    public class var classVar: Int
    {
        get { return _classVar }
        set { _classVar = newValue }
    }
}
BobDickinson
la source
5

Depuis Swift 1.2 (disponible avec Xcode 6.3b1 et les versions ultérieures), staticles propriétés de classe et les méthodes sont prises en charge.

class SomeClass
{
    static var someVariable: Int = 0
}
Andreas Ley
la source
1
Avez-vous remarqué s'ils venaient de désapprouver la classvariable, ou y a-t-il une distinction (utilisée staticpour les structures, classpour les classes)?
Chris Conover
@chrisco L'état des notes de publication staticest un alias pour class final.
Andreas Ley
4

Une solution assez similaire à var dans la portée du fichier mais plus personnalisable et proche du singleton consiste à utiliser une structure qui prend en charge var statique comme propriété de classe

struct PersonSharedData {
    static var backstore = ""
    var data: String {
    get { return PersonSharedData.backstore }
    set { PersonSharedData.backstore = newValue }
    }
}

class Person {
    var shared=PersonSharedData() //<< pseudo class var
    var family: String {
        get { return shared.data }
        set { shared.data=newValue }
    }
    var firstname = ""
    var lastname = ""
    var sexe: Sexe = .Unknown
}
Luc-Olivier
la source
2

Ok, avec la solution de Nikolai qui fait le travail. Je poste mes modifications dans ce fil pour information

var instance: SplitViewController? = nil

class SplitViewController: UISplitViewController {

    class func sharedInstance() -> SplitViewController? {
        return instance;
    }

    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        self.initialization()
    }

    init(coder aDecoder: NSCoder!) {
        super.init(coder: aDecoder);
        self.initialization()
    }

    func initialization() {
        instance = self
    }
}

et par exemple, dans mon appDelegate, je peux accéder à cette méthode statique comme celle-ci

SplitViewController.sharedInstance()!.presentsWithGesture = false
Vincent Saluzzo
la source
Je suis juste curieux, mais la variable "instance" n'est-elle pas une variable globale alors? Cela signifierait que si vous avez une autre classe singleton, votre variable "instance" serait écrasée, non?
Raphael
1

Le libellé de l'erreur implique fortement que ce sera une caractéristique du langage à l'avenir.

Vous souhaiterez peut-être recourir temporairement à la déclaration d'une variable de propriété dans le délégué d'application et à la récupérer à partir de là. Pas idéal, certainement un anti-modèle, mais vous donnerait un endroit central pour récupérer le UISplitViewControllersi nécessaire.

Cezar
la source
Non car dans mon cas, le SplitViewController a été initialisé par le runtime lorsqu'il est réveillé à partir du storyboard, donc je ne peux pas accéder directement à ce contrôleur de vue depuis mon délégué d'application
Vincent Saluzzo
1

Vous devez envelopper les variables de classe dans une variable struct interne

class Store{
    var name:String
    var address:String
    var lat:Int
    var long:Int
    init(name:String, address:String, lat:Int, long:Int){
        self.name = name
        self.address = address
        self.lat = lat
        self.long=long
    }

    private struct FACTORY_INITIALIZED_FLAG { static var initialized: Bool = false
       static var  myStoreList:[Store]?
        static func getMyStoreList()->[Store]{
            if !initialized{
                println("INITIALIZING")
                myStoreList = [
                    Store(name: "Walmart", address: "abcd", lat: 10, long: 20),
                    Store(name: "JCPenny", address: "kjfnv", lat: 23, long: 34)
                ]
                initialized = true
            }
                return myStoreList!
    }
    }
}


var a = Store.FACTORY_INITIALIZED_FLAG.getMyStoreList()

var b = Store.FACTORY_INITIALIZED_FLAG.getMyStoreList()

// only prints INITIALIZING once
Morteza Shahriari Nia
la source
0

Essaye ça:

class var instance: SplitViewController {
    return nil
}
fxchou123
la source
0

Il s'appelle Propriété de type dans Swift.

Vous définissez les propriétés de type avec le mot clé static. Pour les propriétés de type calculées pour les types de classe, vous pouvez utiliser le mot clé class à la place pour permettre aux sous-classes de remplacer l'implémentation de la superclasse. L'exemple ci-dessous montre la syntaxe des propriétés de type stockées et calculées:

struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 1
    }
}
enum SomeEnumeration {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 6
    }
}
class SomeClass {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 27
    }
    class var overrideableComputedTypeProperty: Int {
        return 107
    }
}

En savoir plus sur le lien ci-dessous,

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID254

Lorem
la source