Zmienne klas nie są jeszcze obsługiwane

93

Rozpoczynam projekt z kontrolerem widoku podzielonego jako początkowym kontrolerem widoku i uruchamiam go automatycznie z poziomu scenorysu.

Generalnie aplikacja z tym interfejsem użytkownika ma jeden i tylko jeden kontroler widoku podzielonego jako root, więc tworzę zmienną statyczną w podklasie i ustawiam ją po zakończeniu inicjalizacji.

Więc chcę szybko spróbować tego zachowania.

Przeczytałem podręcznik języka programowania Swift na iBook o właściwościach Type (ze słowem kluczowym static i class) i wypróbowuję fragment kodu do pracy:

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;
    }
}

ale zorientowałem się, kiedy Xcode mówi, że słowo kluczowe class dla właściwości typu nie było jeszcze obsługiwane.

szczegóły błędu na obrazie

Czy masz rozwiązanie, aby to zrobić?

Vincent Saluzzo
źródło
Co się stanie, jeśli zamienisz „let” na „var”?
ZunTzu
Powoduje ten sam błąd.
Cezar
1
To pierwsze ziarno, uspokój się. :) Jeśli książka mówi, że jest obsługiwana i nie jest jeszcze dostępna, to będzie . Nawet błąd mówi „jeszcze” .
akashivskyy
1
Tak @akashivskyy, masz powód, ale może to być i błąd po mojej stronie i ktoś ma rozwiązanie, aby zrobić to zachowanie ...
Vincent Saluzzo
1
@lespommes Apple jest notorycznie powściągliwy w sprawach oczekujących. To dla nich żenujące, że w ich ogromnym wydaniu nowego flagowego języka brakowało takiej standardowej i oczywistej funkcji. Zanim Swift będzie gotowy do poważnego użytku, potrzeba wielu ulepszeń.
Hyperbole

Odpowiedzi:

37

Swift obsługuje teraz zmienne statyczne w klasach. To nie jest dokładnie to samo, co zmienna klasy (ponieważ nie są one dziedziczone przez podklasy), ale zbliża się do niej:

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

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

X.x = 5

println(X.x)
Rachunek
źródło
1
Jak mówi Bill, to nie to samo, ale tego potrzebuję!
Vincent Saluzzo
@VincentSaluzzo, (i Bill) Jaka jest różnica między tą zmienną a zmienną klasy?
Skywinder
Dokumentacja Apple została ostatnio zmieniona, aby zaktualizować stan: developer.apple.com/library/ios/documentation/Swift/Conceptual/ ... W rzeczywistości classsłowo kluczowe może być teraz używane tylko dla obliczonych właściwości, a statyczne są dla wszystkich właściwości typu (w wyliczeniu, klasie lub struct)
Vincent Saluzzo
@skywinder Jak wspomniałem w mojej odpowiedzi, prawdziwe zmienne klas mogą być dziedziczone przez podklasy. Zmienne statyczne nie mogą.
Bill
@VincentSaluzzo Czy Apple aktualizuje swój dokument? developer.apple.com/library/ios/documentation/Swift/Conceptual/ ... spójrz na czwarty akapit: „W przypadku typów wartości (czyli struktur i wyliczeń) można zdefiniować przechowywane i obliczane właściwości typów. W przypadku klas można zdefiniować tylko właściwości typu obliczanego. "
fujianjin6471
73

Osadzenie struktury może działać dobrze jako obejście:

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 }
  }
}

Właściwość typu obliczonego SomeClass.workaroundClassVariable może być następnie używana tak, jakby była właściwością typu przechowywanego.

Glessard
źródło
1
Zadziałało dla mnie - z wyjątkiem tego, że musiałem porzucić „publiczny”, ponieważ XCode 6.0 nie podobało się, że deklarowałem klasę publiczną w klasie wewnętrznej.
Ali Beadle,
Działa świetnie, z wyjątkiem tego, że xcode nie zezwala na zagnieżdżony typ w typie ogólnym ... więc jeśli masz klasę ogólną, wydaje się to raczej beznadziejne, ponieważ możliwe są tylko obliczone właściwości.
BenMQ
19

Wydaje się, że możliwe jest zadeklarowanie zmiennych ze statycznym czasem przechowywania w zakresie pliku (jak w C):

var sharedInstance: SplitViewController? = nil

class SplitViewController: UISplitViewController {
    ....
    func initialization() {
        sharedInstance = self
    }
}
Nikolai Ruhe
źródło
mmmh, czemu nie, ale zdefiniowanie zakresu var w pliku nie powoduje wycieku pamięci przy długim użytkowaniu?
Vincent Saluzzo
@VincentSaluzzo Nie ma różnicy w stosunku do tego, co zrobiłeś przed Swift: przechowuj jedyną instancję w zmiennej statycznej. Nie ma tu nic do wycieku, z wyjątkiem jednej instancji, która żyje tak długo, jak proces.
Nikolai Ruhe
Próbowałem tego na placu zabaw z własną klasą. To nie działa, ponieważ klasa nie została jeszcze zadeklarowana podczas inicjalizacji tej „statycznej” zmiennej. Nie próbowałem tego w projekcie Xcode (chyba tam zadziałało?). Być może będę musiał wymyślić „deklarację przekazywania klasy”, tak jak zawsze robisz to podczas określania protokołu dla klasy.
kawingkelvin
2
Zauważ, że w Xcode 6.0 nie możesz mieć dwóch zmiennych zakresu pliku o tej samej nazwie, nawet jeśli tak jest private.
nschum
@NikolayTsenkov Dokładnie.
Nikolai Ruhe
14

Moją preferowaną metodą jest po prostu użycie prywatnego zakresu pliku var poza klasą, a następnie zaimplementowanie klas / statycznych metod pobierających i ustawiających:

private var _classVar: Int = 0;

class SomeClass
{
    public class var classVar: Int
    {
        get { return _classVar }
        set { _classVar = newValue }
    }
}
BobDickinson
źródło
5

Począwszy od wersji Swift 1.2 (dostępnej z Xcode 6.3b1 i nowszymi) staticobsługiwane są właściwości i metody klas.

class SomeClass
{
    static var someVariable: Int = 0
}
Andreas Ley
źródło
1
Czy złapałeś, jeśli właśnie wycofali classzmienną, czy też istnieje rozróżnienie (kiedyś staticdotyczyło struktur, classklas)?
Chris Conover,
@chrisco W informacjach o wersji staticpodano alias dla class final.
Andreas Ley
4

Rozwiązaniem wystarczająco podobnym do var w zakresie pliku, ale bardziej konfigurowalnym i bliskim singletonowi jest użycie struktury, która obsługuje statyczną zmienną jako właściwość klasy

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
źródło
2

Ok, z rozwiązaniem Mikołaja, które wykonują pracę. Publikuję swoje zmiany w tym wątku w celach informacyjnych

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
    }
}

i na przykład w mojej appDelegate mogę uzyskać dostęp do tej metody statycznej w ten sposób

SplitViewController.sharedInstance()!.presentsWithGesture = false
Vincent Saluzzo
źródło
Jestem po prostu ciekawy, ale czy w takim razie zmienna „instancja” nie jest zmienną globalną? Oznaczałoby to, że jeśli masz inną klasę pojedynczą, zmienna „instancja” zostanie nadpisana, prawda?
Raphael
1

Sformułowanie błędu w dużym stopniu sugeruje, że będzie to funkcja języka w przyszłości.

Możesz tymczasowo skorzystać z zadeklarowania zmiennej właściwości w delegacie aplikacji i pobrać ją stamtąd. Nie jest idealny, na pewno anty-wzór, ale zapewniłby centralne miejsce do odzyskania w UISplitViewControllerrazie potrzeby.

Cezar
źródło
Nie, ponieważ w moim przypadku SplitViewController został zainicjalizowany przez środowisko uruchomieniowe po przebudzeniu ze scenorysu, więc nie mogę bezpośrednio uzyskać dostępu do tego kontrolera widoku od mojego delegata aplikacji
Vincent Saluzzo
1

Musisz umieścić zmienne klasy wewnątrz wewnętrznej zmiennej strukturalnej

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
źródło
0

Spróbuj tego:

class var instance: SplitViewController {
    return nil
}
fxchou123
źródło
0

Nazywa się to Type Property in Swift.

Właściwości typu definiuje się za pomocą słowa kluczowego static. W przypadku właściwości typu obliczonego dla typów klas można zamiast tego użyć słowa kluczowego class, aby umożliwić podklasom przesłonięcie implementacji nadklasy. Poniższy przykład przedstawia składnię przechowywanych i obliczanych właściwości typu:

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
    }
}

Przeczytaj więcej pod linkiem poniżej,

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

Metropolia
źródło