作者:shanks
本周大事是第一届中国 Swift 开发者大会。笔者也请假去北京朝圣。由于大神超多,场面很火爆。可以看出随着 Swift 的开源,加入 Swift 大军的程序猿越来越多。大神们的讲座也很精彩。不虚此行。大家可以通过这里查看大会的精彩内容。本周共整理了5个问题。
本周整理问题如下:
对应的代码都放到了 github 上,有兴趣的同学可以下载下来研究:点击下载
<!--more-->
Question1: Can we expect that one day Swift Compiler will be written in Swift?
问题描述
国外的程序员比较较真,如果逻辑上说得通的表达,就要问清楚是不是这么回事,楼主的问题是:
官网上有一句话写的是,Swift 出现的目的是为了取代那些基于C语言的系列语言(C,C++,OC)。
而 Swift 编译器是使用 C++ 开发出来的,那么是不是意味着,有一天 Swift 编译器可以用 Swift 来重新实现一遍?
问题解答
在swift-evolution刚好有一个proposal 提到了这一点,被否了。原因是 LLVM 也是基于 C++ 实现的,除非重写 LLVM,然后用 Swift 把 C++ 的 API 重新实现一遍。做这个还不如做一些优先级高的事情。
Question2: Type My Custom Class has no subscript members
问题描述
楼主想要实现的功能是,定义一个类的构造函数,传入一个字典,使用字典里面的值,赋值给类中的成员变量。但是在赋值语句处报错。
class Product { var name : String! var type: String! var description: String! var taste: String! var picturePath: String! var pairings: [String] var similar: [String] init(dict: Dictionary<String,AnyObject>) { let props = ["name","type","description","taste","pairings","similar"] for prop in props { self[prop] = dict[prop] //报错:Type 'Product' has no subscript members } } }
问题解答
楼下的解答,也比较巧妙,类需要继承 NSObject,也就具有了 OC 的一些特性。在构造函数中使用 Mirror 得到类的结构信息,进一步得到类的成员变量数组,同时使用 oc 的 setValue(,forKey:) 设置对应的成员变量:
class Product : NSObject { var varDump: AnyObject? var name : String? var type: String? // ... init(dict: Dictionary<String,AnyObject>) { super.init() let a = Mirror(reflecting: self).children.filter { $0.label != nil } for b in a { self.setValue(dict[(b.label ?? "")],forKey: (b.label ?? "varDump")) } } } var propertyInit = [String:AnyObject]() propertyInit["name"] = "John" propertyInit["type"] = "Human" var a = Product(dict: propertyInit) print(a.name ?? "Not initalized") // John print(a.type ?? "Not initalized") // Human
Question3: Implicitly lazy static members in Swift
问题描述
楼主的问题是:
如何理解 struct 中的静态变量(static)?
1、在下面的代码中, Baz 类的构造函数只被调用了一次?
2、Foo 结构体中的静态常量 bar 是延迟加载的?
class Baz { init(){ print("initializing a Baz") } } struct Foo { static let bar = Baz() } var z = Foo.bar z = Foo.bar
问题解答
静态变量(static)本身就是独立于对象存在的。通过类型名来直接访问。且在调用时候只初始化一次,也就是延迟加载的。
由于结构体是值类型,所以可以通过static关键字很方便的实现单例模式。
如果需要绑定到对象,不需要static即可。
struct Foo1 { static let cache = NSCache() // now you might have methods that use this shared `cache` } struct Foo2 { let bar = Baz() } let x = Foo2() let y = Foo2() //x,y 分别调用了 Baz 的构造函数
Question4: How to use Generic type in Swift2
问题链接
问题描述
以下代码会在方法 addNewType 中报错,大家可以不看答案先,想想为啥会报错。这个问题比较初级,但是经常会有人问到。
class TypeA: NSObject { override init() { print("typeA") } } class ObjectA<T: TypeA>: NSObject { var type = [T]() init(type:T) { self.type.append(type) } func addNewType() { let newType = TypeA() self.type.append(newType) // Cannot invoke "append" with an argument list of type '(TypeA)' } }
问题解答
ObjectA 类定义的泛型 T 遵从类 TypeA,定义的数组是[T],进行append操作时候,不能匹配具体的 TypeA,所以报错。可以把 type 换成 [TypeA],因为泛型 T 是表示 TypeA 或者 它的子类。所以[TypeA] 可以 append T 或者 TypeA:
class ObjectA1<T: TypeA>: NSObject { var type = [TypeA]() init(type:T) { self.type.append(type) } func addNewType() { let newType = TypeA() self.type.append(newType) // Cannot invoke "append" with an argument list of type '(TypeA)' } }
Question5: Get nth character of a string in Swift programming language
问题链接
问题描述
以下代码会报错,String 不提供直接的下标访问字符串里面的字符了。这对于 C 和 C++ 程序员来说,有点不太适应。
var string = "Hello,world!" var firstChar:Character = string[0] // Throws error
问题解答
需要自定义subscript来提供对字符串的访问,内部是通过Range来提供范围进行访问,见以下代码:
解法1:
扩展 SequenceType,因为数组的遍历是基于 SequenceType 协议的,所以自然会拥有扩展的方法 frequencies,用来计算元素在数组出现的次数。然后通过 sort 方法输出比较的结果。注意结果数组元素是元组形式。如果想变成与输入相同的结构,要做一下遍历输出。
extension String { subscript (i: Int) -> Character { return self[self.startIndex.advancedBy(i)] } subscript (i: Int) -> String { return String(self[i] as Character) } subscript (r: Range<Int>) -> String { let start = startIndex.advancedBy(r.startIndex) let end = start.advancedBy(r.endIndex - r.startIndex) return self[Range(start: start,end: end)] } } string.characters.first
关于 Swift 2 中对字符串更多的解释,可以查看:https://developer.apple.com/swift/blog/?id=30