【问题标题】:Class variables not yet supported尚不支持类变量
【发布时间】:2014-07-23 18:59:24
【问题描述】:

我以拆分视图控制器作为初始视图控制器开始我的项目,并从情节提要自动启动它。

一般来说,具有此 UI 的应用程序具有 一个且只有一个拆分视图控制器作为根,因此我在子类中创建一个 静态变量 并在初始化时设置它完成。

所以我想用 swift 尝试这种行为。

我在 iBook 上阅读了关于类型属性(带有 static 和 class 关键字)的 Swift 编程语言指南书,并尝试了一段代码来完成这项工作:

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

但我发现 Xcode 说类型属性的 class 关键字还不支持。

您有解决方案吗?

【问题讨论】:

  • 如果将 'let' 替换为 'var' 会发生什么?
  • 产生同样的错误。
  • 这是第一粒种子,冷静点。 :) 如果书上说它受支持但尚不可用,它支持。甚至错误说“还”
  • 是的@akashivskyy,你有理由,但可能是我这边的错误,有人有解决方案来解决这个问题......
  • @lespommes 众所周知,苹果对任何未决的事情守口如瓶。让他们感到尴尬的是,他们大量发布的新旗舰语言缺乏如此标准和明显的功能。在 Swift 正式投入使用之前,需要进行许多改进。

标签: xcode swift


【解决方案1】:

在 Swift 中称为 Type Property

您使用 static 关键字定义类型属性。对于类类型的计算类型属性,您可以使用 class 关键字来允许子类覆盖超类的实现。下面的示例显示了存储和计算类型属性的语法:

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

在下面的链接阅读更多,

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

【讨论】:

    【解决方案2】:

    Swift 现在支持类中的静态变量。这与类变量并不完全相同(因为它们不被子类继承),但它让你非常接近:

    class X {
      static let y: Int = 4
      static var x: Int = 4
    }
    
    println(X.x)
    println(X.y)
    
    X.x = 5
    
    println(X.x)
    

    【讨论】:

    • 正如比尔所说,这是不一样的,但这是我需要的!
    • @VincentSaluzzo,(和比尔)这个和类变量有什么区别?
    • Apple 文档最近已更改以更新状态:developer.apple.com/library/ios/documentation/Swift/Conceptual/… 事实上,class 关键字现在只能用于计算属性,静态用于所有类型属性(在枚举、类或结构中)
    • @skywinder 正如我在回答中提到的,真正的类变量可以被子类继承。静态变量不能。
    • @VincentSaluzzo Apple 是否更新其文档? developer.apple.com/library/ios/documentation/Swift/Conceptual/…看第四段:“对于值类型(即结构体和枚举),可以定义存储和计算类型属性。对于类,只能定义计算类型属性。”
    【解决方案3】:

    从 Swift 1.2(适用于 Xcode 6.3b1 及更高版本)开始,支持static 类属性和方法。

    class SomeClass
    {
        static var someVariable: Int = 0
    }
    

    【讨论】:

    • 您是否发现他们只是弃用了 class 变量,或者有区别(过去是 static 用于结构,class 用于类)?
    • @chrisco 发行说明指出staticclass final 的别名。
    【解决方案4】:

    嵌入一个结构体可以作为一种解决方法工作得很好:

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

    SomeClass.workaroundClassVariable 计算类型属性可以像存储类型属性一样使用。

    【讨论】:

    • 为我工作 - 除了我不得不放弃“公共”,因为 XCode 6.0 不喜欢我在内部类中声明公共类。
    • 效果很好,除了 xcode 不允许在泛型类型中嵌套类型......所以如果你有一个泛型类,它似乎相当绝望,因为只有计算属性是可能的。
    【解决方案5】:

    我的首选方法是在类外部使用私有文件范围 var,然后实现类/静态 getter 和 setter:

    private var _classVar: Int = 0;
    
    class SomeClass
    {
        public class var classVar: Int
        {
            get { return _classVar }
            set { _classVar = newValue }
        }
    }
    

    【讨论】:

      【解决方案6】:

      试试这个:

      class var instance: SplitViewController {
          return nil
      }
      

      【讨论】:

        【解决方案7】:

        您必须将类变量包装在内部结构变量中

        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
        

        【讨论】:

          【解决方案8】:

          在文件范围内与 var 足够相似但更可定制且接近单例的解决方案是使用支持静态 var 作为类属性的结构

          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
          }
          

          【讨论】:

            【解决方案9】:

            Using a dispatch_once singleton model in Swift

            似乎是迄今为止最好的答案,避免使用全局变量。

            【讨论】:

              【解决方案10】:

              好的,使用 Nikolai 的解决方案来完成这项工作。我在此线程中发布我的更改以获取信息

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

              例如,在我的 appDelegate 中,我可以像这样访问这个静态方法

              SplitViewController.sharedInstance()!.presentsWithGesture = false
              

              【讨论】:

              • 我只是好奇,但是变量“实例”不是全局变量吗?这意味着如果您有另一个单例类,您的变量“实例”将被覆盖,对吧?
              【解决方案11】:

              似乎可以在文件范围内声明具有静态存储持续时间的变量(如在 C 中):

              var sharedInstance: SplitViewController? = nil
              
              class SplitViewController: UISplitViewController {
                  ....
                  func initialization() {
                      sharedInstance = self
                  }
              }
              

              【讨论】:

              • mmmh,为什么不呢,但是在文件范围内定义一个 var 在长时间使用不会造成内存泄漏?
              • @VincentSaluzzo 你在 Swift 之前所做的没有什么不同:将唯一的实例存储在静态变量中。这里没有什么可以泄露的,除了与进程一样长的单个实例。
              • 我在操场上用我自己的班级试过这个。它不起作用,因为当你初始化那个“静态”变量时,这个类还没有被声明。我没有在 Xcode 项目中尝试过(我想它一定在那里工作过?)。所以我可能需要像你在为一个类指定协议时一样弄清楚“类前向声明​​”。
              • 请注意,在 Xcode 6.0 中,不能有两个同名的文件范围变量,即使它们是 private
              • @NikolayTsenkov 没错。
              【解决方案12】:

              错误中的措辞严重暗示这将成为未来的语言功能。

              您可能需要暂时在 Application Delegate 中声明一个属性变量并从那里检索它。不理想,绝对是一种反模式,但会给您一个中心位置,以便在需要时检索 UISplitViewController

              【讨论】:

              • 否,因为在我的情况下,SplitViewController 在从情节提要唤醒时由运行时初始化,因此我无法从我的应用程序委托直接访问此视图控制器
              猜你喜欢
              • 2014-06-07
              • 1970-01-01
              • 2011-06-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-12-31
              相关资源
              最近更新 更多