Simple Values
常量用let,变量用var,如果声明时赋值可以不用声明类型,会根据值自动推测类型,如果没有初始值可以用:
声明类型
let implicitInteger = 70
let implicitDouble = 70.0
var myVariable = 42
myVariable = 50
let explicitDouble: Double = 70
float和double可以用以下方式区分,注意4.0-3.9 != 3.0-2.9
哦~ 浮点数处理精度的问题
let e1 : Float = 4.0
let e2 : Double = 4.0
let e3 = Float.init(3.9)
let e4 = 3.9
let f1 = ((e1 - e3) == (Float.init(6.0) - Float.init(5.9)))
let d1 = ((e2 - e4) == (Double.init(6.0) - Double.init(5.9)))
print(type(of: e1))
print(type(of: e2))
print(type(of: e3))
print(type(of: e4))
print(f1)
print(d1)
输出:
Float
Double
Float
Double
true
false
类型转换:
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
print(widthLabel)
用\(变量)
可以将变量值嵌入到字符串,类似stringFormat:
let apples = 3
let appleSummary = "I have \(apples) apples."
print (appleSummary)
创建数组or字典:
var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water"
var occupations = [ "Malcolm": "Captain", "Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
空初始化:
let emptyArray = String[]()
let emptyDictionary = Dictionary<String, Float>()
可以给已知类型的数组或字典赋值[]
以及[:]
,但是如果不知道类型例如声明的时候不能这么做哦,下面的会报错的:
let blankArr = []
Control Flow
if-else,for-in,switch的条件可以不加括号,但是block体一定要用括号括起来哦:
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
if(score)是不OK的,swift木有OC那种可以
if(变量)
的用法,必须是一个bool表达式,例如if(score > 0)
可选类型XXX?
就是这个变量的值可能是nil也可能有值,用if&let可以处理判断可选类型是不是有值:
var optionalString: String? = "Hello"
optionalString = nil
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
} else {
greeting = "Hello, blank"
}
let name2 = optionalName
print(name2)
输出:
Optional("John Appleseed")
如果可选类似是nil,if判断的时候 let name = optionalName
就是false,如果不为nil就会解包并让这个值在括号里面可用。
注意如果可能是nil一定要用可选类型,下面酱紫会报错哦:
var optionalString = "Hello"
optionalString = nil
switch支持各种条件,比OC灵活好多:
let vegetable = "red pepper"
switch vegetable {
case "celery":
let vegetableComment = "Add some raisins and make ants on a log."
print(vegetableComment)
case "cucumber", "watercress":
let vegetableComment = "That would make a good tea sandwich."
print(vegetableComment)
case let x where x.hasSuffix("pepper"):
let vegetableComment = "Is it a spicy \(x)?"
print(vegetableComment)
default:
let vegetableComment = "Everything tastes good in soup."
print(vegetableComment)
}
输出:
Is it a spicy red pepper?
如果木有default这种情况因为string会有很多很多,不写default会报错没有穷尽。
在执行完switch里面的语句以后,代码就会推出了,所以swift可以不写break哦~
for-in可以遍历字典或者array哦~
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
print(largest)
输出25
while循环可以酱紫,我尝试的时候已经不允许用do-while了:
var n = 2
while n < 100 {
n=n*2
}
var m = 2
...
是用于范围的,这种是左右都是闭区间,如果想右边开区间可以0..<3
,和for循环可以结合使用例如:
var firstForLoop = 0
for i in 0...3 {
firstForLoop += I
}
下面这种写法已经被swift抛弃了哦:
var secondForLoop = 0
for (var i = 0; i < 3; i++) {
secondForLoop += 1
}
Functions and Closures
return type用->
来声明,参数用括号的方式声明:
func greet(name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
greet(name:"Bob", day:"Tuesday")
swift可以return很多值哦,虽然只是方便的包了一层~
func getGasPrices() -> (Double, Double, Double) {
return (3.59, 3.69, 3.79)
}
getGasPrices()
还可以通过...
传入不限数量的可变参数哦~
func sumOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf()
sumOf(numbers: 42, 597, 12)
函数还可以内嵌函数哦,当逻辑复杂的时候可以内部分一下~
func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
returnFifteen()
函数还可以返回函数,这里其实很像纳姆达表达式了~
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
let eleven = increment(10)
print(eleven)
当然函数还可以作为参数传给另一个函数~
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 numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)
不需要名字的函数可以用闭包{}
直接声明:
{
(参数列表) ->返回值类型 in
语句组
}
例如:
numbers.map({
(number: Int) -> Int in
let result = 3 * number
return result
})
闭包可以精简一下,如果已知传入或者传出类型,可以省略类型声明:
numbers.map({ number in 3 * number })
你还可以用数字替代参数名称:
sort([1, 5, 3, 12, 2]) { $0 > $1 }
Objects and Classes
定义一个class只要一个名字,variable和method就正常写进去就好啦:
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
使用酱紫:
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
class的初始化函数:
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
}
self可以用于区分参数name和自己的name属性,所有属性都需要被赋值,要么是在初始化init的时候赋值,或者声明的时候类似numberOfSides酱紫,但一定都需要被赋值哦~
deinit方法是在销毁的时候做cleanup滴~
继承用:
声明例如class Square: NamedShape
。如果覆写的方法必须要override
,如果声明override
但父类没有这个方法,或者父类有但是没有声明override
编译都会报错哦~
子类初始化干三件事:
- 设置好自己的属性
- 调用super.init
- 重新设置父类的属性
getter和setter是酱紫的:
private var _name: String?
var name: String? {
get {
return _name
}
set {
_name = newValue
}
}
setter里面传入的值名字固定叫newValue
,如果想改的话可以在setter后面作为参数:
var name: String? {
get {
return _name
}
set(newName) {
_name = newName
print(newName)
}
}
可以参考一下:https://blog.csdn.net/kuangdacaikuang/article/details/80386104
属性分为两种:计算型属性(执行函数返回其他内存地址)&存储型属性(需要开辟空间,以存储数据)
只实现 getter 方法的属性被称为计算型属性,等同于 OC 中的 ReadOnly 属性。
var title: String {
get {
return "Mr " + (name ?? "")
}
}
计算型属性可以使用以下代码简写
var title: String {
return "Mr " + (name ?? "")
}
懒加载属性在第一次调用时,执行闭包并且分配空间存储闭包返回的数值,与 OC 不同的是,lazy 属性即使被设置为 nil 也不会被再次调用:
lazy var title: String = {
return "Mr " + (self.name ?? "")
}()
你还可以在改之前willSet
之后didSet
干点什么:
var numberOfSides: Int = 0 {
willSet {
print("will set")
}
didSet {
print("did set")
}
}
类中的方法相对于函数有一个很大的区别。函数的参数名只能在函数内部使用,但是class里面的func参数名可以在你调用方法是使用。默认情况下,调用时候的名字就是内部的名字,但你也可以指定第二个名字给内部用,或者让调用的时候不用声明名字:
class Counter {
var count: Int = 0
func incrementBy(amount: Int, numberOfTimes times: Int) {
count += amount * times
}
}
var counter = Counter()
counter.incrementBy(amount: 2, numberOfTimes: 7)
如果不想要call时候的名字可以酱紫:
class Counter {
var count: Int = 0
func incrementBy(amount: Int, _ times: Int) {
count += amount * times
}
}
var counter = Counter()
counter.incrementBy(amount: 2, 7)
当操作optional值的时候,你可以在方法,属性和下标的操作前加上?
。如果在?
前面的值是空,则?
之后的一切东西会被忽略,整个表达式为空。否则,如果这个optional值已经被赋值,则在?
之后的所有操作都将被执行。无论怎样,这个表达式的值都是一个optional值。
let optionalS1: String? = nil
let hashS1 = optionalS1?.hashValue
print(hashS1)
let optionalS2: String? = "hhh"
let hashS2 = optionalS2?.hashValue
print(hashS2)
输出:
nil
Optional(-2378297779058712233)
Enumerations and Structures
swift里面的枚举是可以有方法的~
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 "default"
}
}
}
可以指定第一个枚举值的int值,之后的都会依次+1,注意是每个都加一哦,不是一行的是一样的值,类似下面two和three是不一样的哦:
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 .Three:
return "three"
case .King:
return "king"
default:
return "default"
}
}
}
let ace = Rank.Ace
if let convertedRank = Rank.init(rawValue: 3) {
let threeDescription = convertedRank.simpleDescription()
print(threeDescription)
}
输出:three
比较特殊的时候swift可以指定为string或者float~
enum House: String {
case Baratheon = "Ours is the Fury"
case Greyjoy = "We Do Not Sow"
case Martell = "Unbowed, Unbent, Unbroken"
case Stark = "Winter is Coming"
case Tully = "Family, Duty, Honor"
case Tyrell = "Growing Strong"
}
print(House.Greyjoy)
当然你也可以不提供具体值:
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
注意,上面提到的枚举的Hearts成员的两种方式:当给hearts常量赋值的时候,枚举成员Suit.Hearts被列出全名,因为常量没有被显式的指定类型。在switch中,枚举被简写成.Hearts因为self的值已经知道是Suit类型。你可以使用缩写形式在任何值类型已知的情况下。
Swift 中的结构体与 C++ 和 Objective-C 中的结构体有很大的差别,C++ 和 Objective-C 中的结构体只能定义一组相关的成员变量,而 Swift 中的结构体不仅可以定义成员变量(属性),还可以定义成员方法。因此,我们可以把结构体看做是一种轻量级的类。
可以参考一下:https://www.jianshu.com/p/596864f2c672
class 可以继承,而 struct 不可以。
struct也是支持method,init和变量的,它和class唯一的区别是:class传递的时候是传递引用,struct传递的时候是copy的。
Swift 中 struct 是值类型,而 class 是引用类型,所以这篇文章 struct 的行为也可以用到所有的值类型上面,相同地 class 的行为也可以用到引用类型上。
值类型的变量直接包含他们的数据,而引用类型的变量存储对他们的数据引用,因此后者称为对象,因此对一个变量操作可能影响另一个变量所引用的对象。对于值类型都有他们自己的数据副本,因此对一个变量操作不可能影响另一个变量。
// 类赋值
let classCoder = ClassCoder()
classCoder.name = "CJ"
classCoder.age = 18
// classCoder.name=CJ,classCoder.age=18
let classCoder1 = classCoder
classCoder1.name = "NOTCJ"
classCoder1.age = 100
// classCoder.name=NOTCJ,classCoder.age=100,classCoder1.name=NOTCJ,classCoder1.age=100
// 结构体赋值
var structCoder = StructCoder()
structCoder.name = "CJ"
structCoder.age = 18
// structCoder.name=CJ,structCoder.age=18
var structCoder1 = structCoder
structCoder1.name = "NOTCJ"
structCoder1.age = 100
// structCoder.name=CJ,structCoder.age=18,structCoder1.name=NOTCJ,structCoder1.age=100
class 在实例化的时候不能自动把 property 放在 constructor 的参数里面去,想要和 struct 一样的效果就需要我们自己去创建构造函数了。
// 类实例化
let classCoder = ClassCoder()
// class 不能直接用 ClassCoder(name:"CJ",age:18) 必需要自己创建构造函数才可以
classCoder.name = "CJ"
classCoder.age = 18
// 结构体实例化
var structCoder = StructCoder(name:"CJ",age:18)
// 另外一种实例化方法
var structCoder = StructCoder()
structCoder.name = "CJ"
structCoder.age = 18
枚举还可以提供相关值,在switch的时候只看枚举值,不会对比相关值是不是一致,例如下面的Result(String, String)
:
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.")
switch success {
case let .Result(sunrise, sunset):
let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
case let .Error(error):
let serverResponse = "Failure... \(error)"
}
和if let
类似,switch let
干了些神马嘞:
let request = (0,"success")
switch request {
case (0, let state):
state //被输出:success
case (let errorCode, _):
"error code is \(errorCode)"
} // 涵盖了所有可能的case,不用写default了
转成了:
let request = (0,"success")
switch request {
case let (errorCode, state):
state //被输出:success
case (let errorCode, _):
"error code is \(errorCode)"
}
把let放在外面和放在里面为每一个元素单独写上let是等价的。
当你在一个case里使用Value Binding的时候,如果你同时也在它的上一个case里使用了fallthrough,这是编译器所不允许的,你可能会收到这样一个编译错误:
![](https://img.haomeiwen.com/i2262757/1023692dad779504.png)
只要把下面的errorCode去掉就行了,当然,考虑好自己的逻辑。
Protocols and Extensions
使用protocol来声明一个协议。
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
类,枚举,和结构体都可以遵从协议。
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
注意struct中如果方法修改了属性值,需要标记mutating。但class不用啦,大概是因为struct是值copy不是指针copy。
使用extension来添加一个功能给已经存在的类型,就像新的方法和计算性能。你可以使用extension添加一个Protocol。
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
7.simpleDescription
你可以像其他任何一种命名类型一样使用Protocol,例如,创建一个有不同类型的对象的集合,但是这些对象都符合同样的Protocol。当你使用一种被定义为协议类型的类型的值时,那么定义在协议外面的方法将不可用,即使它原本的class有这个属性,但是因为它的类型声明是Protocol就只能读Protocol暴露给外部的接口。
let protocolValue: ExampleProtocol = a
protocolValue.simpleDescription
// protocolValue.anotherProperty // Uncomment to see the error
Generics
泛型就用<type>
来定义:
func repeat<ItemType>(item: ItemType, times: Int) -> ItemType[] {
var result = ItemType[]()
for i in 0..times {
result += item
}
return result
}
repeat("knock", 4)
class,enum和struct都可以定义一个函数的泛型形式。
// Reimplement the Swift standard library's optional type
enum OptionalValue<T> {
case None
case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)
where可以用于要求泛型继承自XXX,实现了XXX协议等,两个类型一致T.GeneratorType.Element == U.GeneratorType.Element
:
func anyCommonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) -> Bool {
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
在简单的情况下,你可以省略where,只在冒号后面写协议或者类的名称。书写<T : Equatable>和<T where T : Equatable>是一样的。
Reference:
https://www.jianshu.com/p/3850ce9b081d
网友评论