1 Swift采用了 Objective-C 的命名参数以及动态对象模型,可以无缝对接到现有的 Cocoa 框架,并且可以兼容 Objective-C 代码。在此基础之上,Swift 还有许多新特性,支持面向过程编程和面向对象编程。
2 通常来说,编程语言教程中的第一个程序应该在屏幕上打印“Hello, world”。在 Swift 中,可以用一行代码实现:
println("hello, world")
在 Swift 中,这行代码就是一个完整的程序。你不需要为了输入输出或者字符串处理导入一个单独的库。全局作用域中的代码会被自动当做程序的入口点,所以你也不需要main函数。你同样不需要在每个语句结尾写上分号。
3 值永远不会被隐式转换为其他类型。如果你需要把一个值转换成其他类型,请显式转换。
let label = "Label" let width = 50 let labelWidth = label + String(width)
4 使用if和let来处理值缺失的情况。有些变量的值是可选的。一个可选的值可能是一个具体的值或者是nil,表示值缺失。在类型后面加一个问号来标记这个变量的值是可选的。
let optionalName: String? = "John Appleseed" var greeting = "Hello!" if let name = optionalName { greeting = "Hello, \(name)" }
5 switch支持任意类型的数据以及各种比较操作——不仅仅是整数以及测试相等。
let vegetable = "red pepper" var vegetableComment = "" switch vegetable { case "celery": vegetableComment = "Add some raisins and make ants on a log." case "cucumber", "watercress": vegetableComment = "That would make a good tea sandwich." case let x where x.hasSuffix("pepper"): vegetableComment = "Is it a spicy \(x)?" default: vegetableComment = "Everything tastes good in soup."
} print(vegetableComment)
打印结果:
Is it a spicy red pepper?
运行switch中匹配到的子句之后,程序会退出switch语句,并不会继续向下运行,所以不需要在每个子句结尾写break。
6 函数
(1)函数的参数数量是可变的,用一个数组来获取它们:
func sum(numbers: NSInteger ...) -> NSInteger { var sum = 0 for number in numbers { sum += number } return sum
}
sum()
sum(1)
sum(1,2,3)
(2) 函数可以嵌套。被嵌套的函数可以访问外侧函数的变量,你可以使用嵌套函数来重构一个太长或者太复杂的函数。
func returnFifteen() -> NSInteger { var a = 10 func addFive() { a += 5 } addFive() return a } returnFifteen()
(3) 函数可以作为另一个函数的返回值
func makeIncrement(a: Int) -> (Int -> Int) { func addOne(m: Int) -> Int { return a + m } return addOne }
let increment = makeIncrement(10)
let n = increment(5)
print(increment)
print(n)
打印结果:
(Function)
15
(4)函数也可以当做参数传入另一个函数
func hasAnyMatches(list: [Int], condition: Int -> Bool) -> Bool { for item in list { if condition(item) { return true } } return false } func lessThanTen(number: Int) -> Bool { return number < 10 } let list = [20, 19, 7, 12] hasAnyMatches(list, condition: lessThanTen)
(5)函数实际上是一种特殊的闭包,你可以使用{}来创建一个匿名闭包。使用in来分割参数并返回类型。
let a = list.map({ (number: Int) -> Int in let result = number % 2 != 0 ? 0 : number * 3 return result }) print(a) //{60,0,0,36}
有很多种创建闭包的方法。如果一个闭包的类型已知,比如作为一个回调函数,你可以忽略参数的类型和返回值。单个语句闭包会把它语句的值当做结果返回。
你可以通过参数位置而不是参数名字来引用参数——这个方法在非常短的闭包中非常有用。当一个闭包作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面。
(参考文章:swift深入理解闭包)
7 对象和类
创建类的时候并不需要一个标准的根类,所以你可以忽略父类。
class Shape { var numberOfSides = 0 var name: String? init(name: String) { self.name = name } func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } }
属性可以有 getter 和 setter 。如果你不需要计算属性但是需要在设置一个新值之前或者之后运行一些代码,可以使用willSet和didSet。
8 枚举和结构体
使用enum来创建一个枚举。就像类和其他所有命名类型一样,枚举可以包含方法。
enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func simpleDescription() -> String { switch self { case .Ace: return "ace" case .Jack: return "jack" case .Queen: return "queen" case .King: return "king" default: return String(self.rawValue) } } } let ace = Rank.Ace ace.rawValue //1 ace.simpleDescription() //"ace" let two = Rank.Two two.rawValue //2 two.simpleDescription() //"2" let king = Rank.King king.simpleDescription() //"king"
在上面的例子中,枚举原始值的类型是Int,所以你只需要设置第一个原始值。剩下的原始值会按照顺序赋值。
枚举的成员值是实际值,并不是原始值的另一种表达方法。实际上,如果原始值没有意义,你不需要设置。
enum Suit { case Spades, Hearts, Diamonds, Clubs func simpleDescription() -> String { switch self { case .Spades: return "spades" case .Hearts: return "hearts" case .Diamonds: return "diamonds" case .Clubs: return "clubs" } } } let hearts = Suit.Hearts let heartsDescription = hearts.simpleDescription()
使用struct来创建一个结构体。结构体和类有很多相同的地方,比如方法和构造器。它们之间最大的一个区别就是 结构体是传值,类是传引用。
struct Card { var rank: Rank var suit: Suit func simpleDescription() -> String { return "The \(rank.simpleDescription()) of \(suit.simpleDescription())" } } let card = Card(rank: .Queen, suit: .Diamonds) card.simpleDescription()
练习:创建一副完整的扑克牌并把每张牌的rank和suit对应起来。代码如下
//给Rank添加一个方法 func allValues() -> [String] { return ["ace", "1", "2", "3", "4", "5", "6", "7", "8", "9", "jack", "queen", "king"] } //给Suit添加一个方法 func allValues() -> [String] { return ["spades", "hearts", "diamonds", "clubs"] } //给card添加一个方法 func allDeck() -> [String] { let rankArray = rank.allValues() let suitArray = suit.allValues() var allDeck = [String]() for oneRank in rankArray { for oneSuit in suitArray { allDeck.append(oneRank + " " + oneSuit) } } return allDeck }
let card = Card(rank: .Queen, suit: .Diamonds) card.allDeck()
一个枚举成员的实例可以有实例值。相同枚举成员的实例可以有不同的值。创建实例的时候传入值即可。实例值和原始值是不同的:枚举成员的原始值对于所有实例都是相同的,而且你是在定义枚举的时候设置原始值。
例如,考虑从服务器获取日出和日落的时间。服务器会返回正常结果或者错误信息。
enum ServerResponse { case Result(String, String) case Error(String) } let success = ServerResponse.Result("6:00 am", "8:09 pm") let failure = ServerResponse.Error("Out of cheese.") var serverResponse = "" switch success { case let .Result(sunrise, sunset): serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)." case let .Error(error): serverResponse = "Failure... \(error)" } print(serverResponse) //"Sunrise is at 6:00 am and sunset is at 8:09 pm.\n"
8 接口和扩展
使用protocol来声明一个接口。
protocol ExampleProtocol { var simpleDescription: String {get} mutating func adjust() }
类、枚举和结构体都可以实现接口。
class SimpleClass: ExampleProtocol { var simpleDescription: String = "simple class" var anotherProperty: Int = 12345 func adjust() { simpleDescription += "\(anotherProperty)" } } var a = SimpleClass() a.adjust() let b = a.simpleDescription print(b) //"simple class12345\n" struct SimpleStructure: ExampleProtocol { var simpleDescription: String = "simple structure" var adjusted: Int = 12345 mutating func adjust() { simpleDescription += "\(adjusted)" } } var m = SimpleStructure() m.adjust() let n = m.simpleDescription print(n) // "simple class12345\n"
注意声明SimpleStructure时候mutating关键字用来标记一个会修改结构体的方法。SimpleClass的声明不需要标记,任何方法因为类中的方法经常会修改类。
使用extension来为现有的类型添加功能,比如添加一个计算属性的方法。你可以使用扩展来给任意类型添加协议,甚至是你从外部库或者框架中导入的类型。
extension Int: ExampleProtocol { var simpleDescription: String { get { return "The number is \(self)" } } mutating func adjust() { self += 40 } } var d = 5 d.simpleDescription d.adjust() print(d) //"45\n"
9 泛型
在尖括号里写一个名字来创建一个泛型函数或者类型
func repeatValue<itemType>(item: itemType, times: Int) -> [itemType] { var result = [itemType]() for _ in 0 ..< times { result.append(item) } return result } repeatValue(3, times: 4) //[3,3,3,3] repeatValue("string", times: 3) //["string","string","string"]