转载

每周 Swift 社区问答 2015-12-30

作者: shanks

本周整理问题如下:

  • Swift regular expressions
  • Storing a reference to array in swift
  • What’s the difference between [String!] and [String]!
  • How can I filter dictionary [[String:String]]
  • Why ‘self.self’ compiles and run in swift?

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

Question1: Swift regular expressions

Q1链接地址

问题描述

楼主直接就问:如何在 swift 中使用 [a-zA-Z]+@[a-zA-Z]+.[a-zA-Z] 这样的正则表达式?

问题解答

目前在 Swift 中使用正则表达式,还是直接调用 oc 里面的 NSRegularExpression 来完成的。

喵神有一个 tips 专门介绍了这个知识点:

http://swifter.tips/regex/

下面是跟帖的代码,解决了问题:

let test = "someone@somewhere.com"

do {
let regex = try NSRegularExpression(pattern: "[a-zA-z]+@[a-zA-Z]+.[a-zA-Z]", options: [])
if regex.firstMatchInString(test, options: [], range: NSMakeRange(0, test.characters.count)) != nil {
print("matched")
} else {
print("not matched")
}
} catch let error as NSError {
print(error.localizedDescription)
}

Question2: Storing a reference to array in swift

Q2链接地址

问题描述

Swift 类中定义的方法,传入参数默认是值拷贝,也就是说,即使方法内部改变参数值,传入的参数原始值是不会改变的。

楼主纠结如何实现引用拷贝,也就是,赋值给类中的属性以后,改变了属性的值,传入的参数也会跟着改变,见代码如下:

import Foundation

class Foo {
var foo : Array<Int>

init(foo: Array<Int>) {
self.foo = foo
}

func modify() {
foo.append(5)
}
}

var a = [1,2,3,4]
let bar = Foo(foo: a)
bar.modify()
print(a) // My goal is that it will print 1,2,3,4,5

问题解答

实际上,使用inout,也不能解决问题,inout 只是应用在方法内部直接改变传入值的时候有用,而上例中,是先赋值给了类的一个属性,改变了属性的值,而没有改变传入参数值。因为 Array 是值类型,赋值默认为值拷贝:

class Foo1 {
var foo : Array<Int>

init(foo: Array<Int>) {
self.foo = foo
}

func modify() {
foo.append(5)
}
}

let bar1 = Foo1(foo: a)
bar.modify()
print(a) // 还是没有改变 a

以下代码是跟帖中提供的解决方案,使用 UnsafeMutablePointer ,也就是 c 语言中的 int * 指针来达成指向内存的一致。从而在修改时候,能够保持一致。但是强烈不推荐此种做法,因为 Swift 强调的类型安全丢失了。

class Foo2 {
var foo : [Int]
var pInner: UnsafeMutablePointer<Int>

init(foo: [Int]) {
pInner = UnsafeMutablePointer(foo)
self.foo = Array(UnsafeBufferPointer(start: pInner, count: foo.count))
}

func modify(inout pOuter: UnsafeMutablePointer<Int>) {
foo.append(5) // <-- foo gets new memory adress
pInner = UnsafeMutablePointer(foo)
pOuter = pInner
}
}

var pOuter: UnsafeMutablePointer<Int> = UnsafeMutablePointer(a)
var bar2 = Foo2(foo: a) // 'bar.foo' now at same address as 'a'
print(bar2.foo) // [1,2,3,4]
bar2.modify(&pOuter) // -> [1,2,3,4,5]
a = Array(UnsafeBufferPointer(start: pOuter, count: bar.foo.count))

/* Same pointer adress, OK! */
print(bar2.pInner)
print(pOuter)

/* Naturally same value (same address in memory) */
print(bar.foo)
print(a)

此问题其实在实际编码中,应该尽量避免,一个类,去改变外部的值,违背了类的封装性。

Question3: What’s the difference between [String!] and [String]!

Q3链接地址

问题描述

楼主是新手,新手最多的几个问题之一就是对 Optional 的理解。楼主的问题是:[String!] and [String]! 的区别是什么?

问题解答

  • [String!] 是一个包含隐式解包 Optional String 的数组,数组的值可以为 nil。

  • [String]! 是一个隐式解包 Optional 的数组,数组类型是 String,可以直接对这个数组赋值为nil,但是因为数组元素类型是 String,所以数组元素不能为nil

let list0: [String!] = ["Hello", nil, "world", nil]

let list1: [String]! = nil
let list2: [String]! = ["Hello", "world"]

Question4: How can I filter dictionary [[String:String]]

问题链接

Q4链接地址

问题描述

楼主有一个二维数组,想通过数组中的 type 字段,进行过滤。于是他写出了如下报错的代码:

var data = [["type":"Sport", "model":"R6"],["type":"Enduro", "model":"Tenerre"],["type":"Chopper", "model":"Intruder"]]
//data.filter({ (type: String) -> Bool in
// return true
//})

问题解答

数组 filter 方法的定义:

filter(includeElement: (T) -> Bool) -> T[]

在这个例子中,数组是二维的,所以 T = [String:String],也是一个数组。所以正确答案应该是:

let filteredData = data.filter { (dict:[String:String]) -> Bool in
return dict["type"] == "Sport"
}

Question5: Why ‘self.self’ compiles and run in swift?

问题链接

Q5链接地址

问题描述

楼主的问题是:为什么 self.self 这样的写法在其他语言会报错,而 Swift 中,不会报错:

class test {
var someProperty = ""
func test() {
print(self.self.someProperty)
}
}

问题解答

实际上,无论支持还是不支持这种语法,一个 self,应该就足够了。跟帖也在质疑这种用法的实用性在那?例如如下的形式,这样写与只带一个 self,没什么区别:

let s = "Hello".self.self.self.self.self.self.self.self

let s1 = "Hello".self
正文到此结束
Loading...