每周 Swift 社区问答 2016-01-13

iOS海马 2019-06-20

作者:shanks

本周大事是第一届中国 Swift 开发者大会。笔者也请假去北京朝圣。由于大神超多,场面很火爆。可以看出随着 Swift 的开源,加入 Swift 大军的程序猿越来越多。大神们的讲座也很精彩。不虚此行。大家可以通过这里查看大会的精彩内容。本周共整理了5个问题。

本周整理问题如下:

  • Can we expect that one day Swift Compiler will be written in Swift?

  • Type My Custom Class has no subscript members

  • Implicitly lazy static members in Swift

  • How to use Generic type in Swift2

  • Get nth character of a string in Swift programming language

对应的代码都放到了 github 上,有兴趣的同学可以下载下来研究:点击下载

<!--more-->

Question1: Can we expect that one day Swift Compiler will be written in Swift?

Q1链接地址

问题描述

国外的程序员比较较真,如果逻辑上说得通的表达,就要问清楚是不是这么回事,楼主的问题是:

官网上有一句话写的是,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

Q2链接地址

问题描述

楼主想要实现的功能是,定义一个类的构造函数,传入一个字典,使用字典里面的值,赋值给类中的成员变量。但是在赋值语句处报错。

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

Q3链接地址

问题描述

楼主的问题是:
如何理解 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

问题链接

Q4链接地址

问题描述

以下代码会在方法 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

问题链接

Q5链接地址

问题描述

以下代码会报错,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

相关推荐