代码

static 和 class

在非 class 的类型上下文中,我们统一使用 static 来描述类型作用域。这包括在 structenum 中表述类型方法和类型属性时。在这两个值类型中,我们可以在类型范围内声明并使用存储属性,计算属性和方法。

class 关键字相比起来就明白许多,是专門用在 class 类型的上下文中的,可以用来修饰类方法以及类的计算属性。但是有一个例外,class 中现在是不能出现 class 的存储属性的。

class MyClass {
     class var bar: Bar?
}

编译器会报一个错误:

class variables not yet supported

在 Swift 1.2 及之后,我们可以在 class 中使用 static 来声明一个类作用域的变量。也就是:

class MyClass {
     static var bar: Bar?
}

的写法是合法的。有了这个特性之后,像 单例 的写法就可以回归到我们习惯的方式了。

有一个比较特殊的是 protocol。在 Swift 中 classstructenum 都是可以实现某个protocol 的。那么如果我们想protocol 里定义一个类型域上的方法或者计算属性的话,应该用哪个关键字呢?答案是使用 static 进行定义。在使用的时候,structenum 中仍然使用 static ,而在 class 里我们既可以使用 class 关键字,也可以用 static ,它们的结果是相同的。

protocol MyProtocol {
    // 在 protocol 中使用 static 定义类型域上的方法和计算属性
    static func foo() -> String
}

struct MyStruct: MyProtocol {
    // 在 struct 中使用 static 定义类型方法和类型属性
    static func foo() -> String {
        return "MyStruct"
    }
}

enum MyEnum: MyProtocol {
    // 在 enum 中使用 static 定义类型方法和类型属性
    static func foo() -> String {
        return "MyEnum"
    }
}


class MyClass: MyProtocol {
    // 在class中既可以使用class 定义类方法和计算属性
    class func foo() -> String {
         return "MyClass.foo()"
    }
    // 也可以使用static
    static func bar() -> String {
        return "MyClass.bar()"
    }

}

单例

  1. 因为在Swift中可以无缝直接使用 GCD, 所以我们可以很方便的把 OC 实现单例的方式用 Swift 改写:
class MyManager {
    class var sharedManager: MyManager {

        //在swift1.2之前并不支持存储类型的类属性,所以我们需要使用struct来存储类型变量。
        struct Static {
            static var onceToken: dispatch_once_t = 0
            static var staticInstance: MyManager? = nil
        }

        dispatch_once(&Static.onceToken) {
            Static.staticInstance = MyManager()
        }
        return Static.staticInstance!
    }
}
  1. 可以使用 let 保证线程安全:
class MyManager {

    class var shareManager: MyManager {
        struct Static {
            static let sharedInstance: MyManager = MyManager()
        }
        return Static.sharedInstance
    }
}
  1. 由于Swift 1.2 之前 class 不支持存储式的 property,我们想要使用一个只存在一份的属性时,就只能将其定义在全局的 scope 中。值得庆幸的是,在 Swift 中是有访问级别的控制的,我们可以在变量定义前面加上 filePrivate 关键字,使这个变量只在当前文件中可以被访问。这样我们就可以写出一个没有嵌套的,语法上也更简单好看的单例了。swift 1.2 之前最佳实践的做法:
fileprivate let sharedInstance = MyManager()

class MyManager {
    class var sharedManager: MyManager {
        return sharedInstance
    }
}
  1. swift 1.2及以后,可以在 class 中使用 static 来声明一个类型作用域的变量。
class MyManager {
    static let sharedManager = MyManager()
    private init() {}
}

这种写法不仅简洁,而且保证了单例的独一无二。初始化变量的时候,Apple将会把这个初始化包装在一次 swift_once_block_invoke 中,以保证它的唯一性。对于所有的全局变量,Apple都会在底层使用这个类似 dispatch_once 的方式来确保只以 lazy 的方式初始化一次。

另外,我们在这个类型中加入了一个私有的初始化方法,来覆盖默认的公开初始化方法,这让项目的其他地方不能通过 init 来生成自己的 MyManager 实例,也保证了类型单例的唯一性。

如果你需要类似defaultManager的形式的单例(也就是说这个类的使用者可以创建自己的实例)的话,可以去掉这个私有的init方法。

results matching ""

    No results matching ""