Swift

Swift

支持“面向对象编程”或者“Functional 编程”【利用generics和extensions(default implementations)-》结合protocol】

CountableRange

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20


// CountableClosedRange: [0,2] 可数的闭区间
let rangea = 0...2
// CountableRange: [0,2) 可数的开区间
let rangeb = 0..<2
// ClosedRange: [0.1,2.1] 不可数的闭区间
let rangec = 0.1...2.1
// Range: [0.1,2.1) 不可数的开区间
let ranged = 0.1..<2.1

//可数区间能直接for循环
for i in 1...10{

}

//不可数区间不能直接for循环,需要利用stride创建可数范围
for i in stride(from:0.5, through:15.25, by:0.3){

}

let

let 所声明的变量统统为不可变的变量。是不能被再次赋值,包括修改。这一点跟 OC 中的不可变类型有区别【如NSMutableArray 与NSArray 】,OC 中是不能被修改,但是可以被重新赋值。

var

var 所声明的变量统统为可变的变量。【didSet关注更新】

1
2
3
4
5
6
7
8
9
private(set) var flipCount = 0 {
didSet {
let attributes: [NSAttributedStr ingKey :Any] = [
.strokeWidth : 5.0,
.strokeColor :
]
let attributedString = NSAttributedString(string: "Flips: \(flipCount)", attributes: attributes)
flipCountLabel .attributedText = attr ibutedString
}

as 与 is

Swift—— is和 as、 as? 、 as! 区别

swift里 as、as!、as?区别

is用来判断是否为某种类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protocol Runnable {func run() }
class Persion {}
class Student:Persion,Runnable{
func run() {
print("跑起来")
}
func study(){
print("study")
}
}

//判断类型
var stu: Any = 10
print(stu is Int)//true
stu = "jack"
print(stu is String)//true
stu = Student()
print(stu is Persion)//true
print(stu is Student)//true
print(stu is Runnable)//true

as用来类型转换

【“Guaranteed conversion”】

(1)从派生类转换为基类,向上转型(upcasts)
(2)消除二义性,数值类型转换
(3)switch 语句中进行模式匹配

【”Forced conversion“】

as! 向下转型(Downcasting)时使用。由于是强制类型转换,如果转换失败会报 runtime 运行错误。

as? 和 as! 操作符的转换规则完全一样。但 as? 如果转换不成功的时候便会返回一个 nil 对象。成功的话返回可选类型值(optional),需要我们拆包使用。

元组(tuple)

1
2
3
4
5
6
7
8
9
10
11
12
let x: (String ,Int, Double) = ("hello", 5, 0.85) // the type of X is"a tuple"
let (word, number, value) = x
// this names the tuple elements when accessing the tuple
print (word)// prints hello
print (number) // prints 5
print(value) // prints 0.85
//标记元组属性名
let x: (w: String, i: Int, v: Double) = ("hello", 50.85)
print(x.w) // prints hello
print(x.i) // prints 5
print(x.v) // prints 0.8
let (word, number, value) = x

常用于函数返回值

1
2
3
4
func getSize() -> (weight: Double, height: Double) { return (250, 80) } 
let x = getSize()
print("weight is \(x.weight)") // weight is 250
print("height is \(getSize().height)") // height is 80

计算属性(Computed Properties)

The value of a property can be computed rather than stored【OC中虽然没有存储属性和计算属性的概念,但@property关键字实际上也间接的完成了存储属性+计算属性的自动创建。】

OC的@property与Swift的存储属性/计算属性类比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//A typical stored property looks something like this 
//存储属性用于存储一些值或引用
var foo: Double

//A computed property looks like this
// 提供get/set方法处理其他的属性或逻辑操作,但get/set方法中没法对计算属性自身进行修改,否则会造成死循环。
var foo: Double {
// 只有get便是readonly
get {
// return the calculated value of foo
}
set (newValue) {
// do something based on the fact that foo has changed to newValue
}
}

lesson 中
var index0f TheOneAndOnlyF aceUpCard: Int? {
//get/set方法中没法对计算属性自身进行修改,否则会造成死循环。 编译器会报警告,在运行中,因为计算属性在自己的get/set方法中操作计算属性,本质还是调用计算属性的get/set方法,所以最后肯定都是以陷入死循环而告终
get {
var foundIndex: Int?
for index in cards. indices {
if cards[ index].isFaceUp {
if foundIndex == nil {
foundIndex = index
} else {
return nil
}
}
return foundIndex
}
set {
for index in cards. indices {
cards[index].isFaceUp = (index == newValue)
}
}
}

//以下Swift代码实现的功能就跟OC中的@property实现的功能一样
var _name: String?
var name: String? {
get {
return _name
}
set {
_name = newValue
}
}

Accsess Control

  • private - this means “only callable from within this ob ject”【只允许在当前定义体内使用。】
  • private(set) - this means“this property is readable outside this object, but not settable”【此属性在对象之外可读,但不可设置】
  • fileprivate - accessible by any code in this source fle【当前源文件访问。】
  • internal - this is the default, it means “usable by any object in my app or framework ”【本模块能访问。不写访问控制关键字,默认为 internal。】
  • public - (for frameworks only) this can be used by objects outside my framework【本模块和其他模块都能访问,不允许其他模块继承或重写。】
  • open - (for frameworks only) public and objects outside my framework can subclass this【本模块和其他模块都能访问,只能应用在类或者类成员上。允许其他模块继承或重写。】

extension

swift 扩展(Extensions)

就是为一个已有的类、结构体、枚举类型或者协议类型添加新功能。 Objective-C 中的分类类似【但Swift 的扩展没有名字】。

断言(Assertion)

assert

断言可以引发程序终止,并不是被设计用来避免不在发生无效情况的。在那些无效条件有可能触发的情况下,断言是一种有效的调试手段,可以确保在应用发布之前,在开发过程中就可以关注这些条件。

1
2
3
4
5
6
7
8
let number = 3
//第一个参数为判断条件,第二个参数为条件"不满足"时的打印信息。
assert(number > 3, "number 不大于3")
//如果断言被触发(number <= 3时),将会强制结束程序,并打印相关信息:
assertion failed: number 不大于3: file /Users/mac/Desktop/test/test/ViewController.swift, line 17


assert(numberOfPairsOfCards > 0"Concentration. init(\(numberOfPairsOfCards)): chosen index not in the chrds")

enum

与C,Objective-C中的枚举相比,Swift中枚举功能更强大。它支持很多只有类才有的特性,如: Properties, Methods, Initialization, Extensions, Protocols.

(1)Swift枚举情况在创建时不分配默认整数值。

(2)变量只能是计算变量

Swift 枚举(enum)详解【注意递归枚举】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//Associated Data
enum FastFoodMenuItem {
case hamburger ( numberOfPatties: Int )
case fries(size: FryOrderSize)
case drink(String, ounces: Int) // the unnamed String is the brand, e.g. "Coke"
case cookie

func isIncludedInSpecialOrder(number: Int) -> Bool {
switch self {
case .hamburger( let pattyCount): return pattyCount == number
case .fries, .cookie: return true // a drink and cookie in every specialorder
case .drink(_, let ounces): return ounces == 16 // & 16oz drink of any kind
}
}

//mutating:只用在值类型中
mutating func switchToBeingACookie() {
self = .cookie // this works even if self is a .hamburger, .fries or .drink
}

var calories: Int { // calculate and return caloric value here }

}

enum FryOrderSize {
case large
case small
}

var menuItem = FastFoodMenuItem. drink("Coke", ounces:32 )
switch menuItem {
case . hamburger( let pattyCount): print("a burger with \(pattyCount) patties!")
case . fries(let size): print("a \(size) order of fries !")
case .drink( let brand ,
let ounces): print("a \(ounces)oz \ (brand)")
case .cookie: print("a cookie!")
}
// 结果 : a 32oz Coke

mutating

Swift关键字(mutating)【编译成.sil文件,很强~新技能】

mutating:只用在值类型中,默认情况下,实例方法中是不可以修改值类型的属性,使用mutating后可修改属性的值

structure和enumeration是值类型(value type)-》通过复制传递【写时复制】,不会存在堆中

class是引用类型(reference type)。

inout

修改的是参数类型,在函数的声明中,默认的参数都是不可变的【想要可变,需要添加inout关键字】这样就变成传递的过程中传递的是地址【即引用】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func swap(_ a: inout Int,_ b: inout Int) {
let temp = a
a = b
b = temp
}

var age = 10
var age2 = 30

//传递的是地址
swap(&age, &age2)

print(age)
print(age2)

optional

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
enum
Optional<T> { // a generic type, like Array<Element> or Dict ionary<Key, Va lue>
case none
case some(<T>) / the some case has associated data of type T
}
But this type is So important that it has a lot of special syntax that other types don't have

//? 声明此时并不确定是否有值,所以只在有值时调用后面方法
var hello: String? 等于 var hello: Optional<String> = .none
var hello: String? = "hello" 等于 var hello: Optional<String> =.some("hello")
var hello: String? = nil 等于 var hello: Optional<String> = .none

// ??
let X: String? = ...
let y = x ?? "foo"
等于 遍历该枚举类型,并switch
switch X {
case .none: y = "foo"
case .some(let data): y = data
}

// ? 链条
let x:
String?
let
y = x?.foo()?.bar?.z
等于
switch X {
case .none: y = nil
case .some(let data1):
switch data1.foo() {
case .none: y = nil
case . some(let data2):
switch data2.bar {
case . none: y = nil
case .some(let data3): y = data3.z
}
}
}

// !
let hello: String? = ...
print(hello!)
//等于 明确声明此时一定有值,无论什么情况都调用后面的方法。
switch hello {
case .none: // raise an exception (crash)
case . some(let data): print(data)
}


//if
if let greeting = hello {
print (greeting)
} else {
// do something else
}
等于 greeting为空就另外处理
switch hello {
case . some(let data): print (data)
case .none: { // do something else }
}

syntactic sugar(这只是语法糖而已。)

?

声明可选,声明此时并不确定是否有值,所以只在有值时调用后面方法

??

  1. 双问号的意思是,判断前面的表达式的值为nil。否为前面的表达式的值,是为后面的值

  2. 当值为0时,是不走后面的值的

    1
    2
    //类似三元运算符
    return emoji[card.identifier] ?? "?"

!

无须初始化,明确声明此时一定有值,无论什么情况都调用后面的方法。否则为nil,调后面的方法出现exception

_

忽略

nil

表示未设置的选项

swift中的Any与oc中的id

Swift 中的 Any ,它描述了一个任意类型的值,无论是类、枚举、结构体还是其他 Swift 类型。这个变化致使 Objective-C API 在 Swift 中更加灵活,因为 Swift 中定义的值类型可以传送到 Objective-C API 中并作为 Swift 类型展开,消除了手动“包装”类型的需求。这些好处同时扩展了集合:Objective-C 集合类型 NSArray 、 NSDictionary 以及 NSSet ,它先前只接受 AnyObject ,现在可以包含 Any 类型。对于哈希容器,比如 Dictionary 和 Set ,现在有新的类型 AnyHashable 能保存任何遵循 Swift 中Hashable 协议的类型。

Objective-C Swift 2 Swift 3
id AnyObject Any
NSArray * [AnyObject] [Any]
NSDictionary * [NSObject: AnyObject] [AnyHashable: Any]
NSSet * Set Set

ARC

strong
weak 【常用于outlet、delegation等指向引用类型的optional 指针】
unowned【closures】

protocol

OC和Swift中的protocol

OC和SwiftProtocol的共同点

本质都是抽取不同类的共同方法和属性(声明),供遵循协议的类或对象使用。

都可以通过定义协议实例deleagate,来实现委托代理模式。

PS:类比继承的概念,继承父类的方式比较险隘,子类和父类只能为同一基类,且方法都有实现,需在子类中override,并不能把方法和属性完全独立出来,且不能多继承。

OC和SwiftProtocol的区别(核心)

OC中的协议更单纯的受限于委托代理的含义,多用于跨类的传值和回调通知。

而Swift是面向协议编程,其思想是通过抽取不同类中的相同方法和属性,实现模块化减少耦合。

Swift可以通过协议extension扩展,缺省实现协议的方法(OC不行)。

Swift的协议不需要单独声明协议对象(id <Deleagate> delegate)和指定代理(delegate = self),只需要遵循协议的类实现声明,或使用协议的缺省实现。

使用

(1)属性要求:只能是计算属性。指定其读写性{ get set };var关键字修饰;可用static关键字实现类属性;不能设置默认值(默认值被看做是一种实现)。

(2)方法要求:
方法不能添加默认实现和默认参数(可使用扩展实现);
可用static关键字实现类方法;mutating修饰,方法实现时,满足结构体或枚举内部修改属性变量的情况。
协议的方法其实没有可选实现,加@objc optional是为了对应OC中的optional。

(3)协议可以作为类型使用;可看做一种特殊泛型。

(4)在协议后加class(或anyobject),标识只能被类类型遵守struct不行。

(5)在协议前加@objc,表示只能被OC或@objc的类遵循。

Delegation

定义协议实例deleagate

Function Types

You can declare a variable (or parameter to a method or whatever) to be of type “function Types“

1
2
3
4
5
6
7
var operation: (Double) -> Double
//This is a var called operation
//It is of type "function that takes a Double and returns a Double"
//You can assign it like any other variable...
operation = sqrt // sqrt is just a function that takes a Double and returns a Double
//You can“ call" this function using syntax very similar to any function call ..
let result = operation(4.0)//计算4的平方根

closures【引用类型,同class】

Swift 闭包(Closures

类似Objective-C中的Block 或者Java 中的lambdas

闭包就是一个独立的函数,一般用于捕获和存储定义在其上下文中的任何常量和变量的引用。

1
2
3
4
5
6
7
8
9
10
let primes = [2.0, 3.0, 5.0, 7.0, 11.0]
let negativePrimes = primes.map({ -$0 }) // [-2.0, -3.0, -5.0, -7.0, -11.0]
let invertedPrimes = primes.map() { 1.0/s0 } // [0.5,0.333, 0.2, etc. ]
let primeStrings = primes.map { String($0) } // ["2.0","3.0”, "5.0","7.0","11. 0"]

// 特别适用于lazy property initialization.
var someProperty: Type = {
// construct the value of someP roperty here
return <the constructed value>
}() //到()之前调用{}

【待补充 closures循环引用】

throw Error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

func save( ) throws
//You must put calls to functions like this in a do { } block and use the word try to call them
do {
try context. save( )
} catch let error {
// error will be something that implements the Error protocol, e.g., NSError
// usually these are enums that have associated values to get error details
throw error // this would re-throw the error (only ok if the method we are in throws )
}
If you are certain a call will not throw, you can force try with try!
try! context.save() // will crash your program if save() actually throws an error

Or you can conditionally try, turning the return into an Optional (which will be nil if fail)
let x = try? errorProneFunctionThatReturnsAnInt() // x will be Int?

win 与 macOS

苹果键盘 苹果符号 对应window键盘
Cammand win键
Option alt键
Control ^ ctrl键
Shift Shift键
Caps Lock ⇪ 或者 . 中/英 Caps Lock键
---------------- 本文结束 ----------------

本文标题:Swift

文章作者:Pabebe

发布时间:2022年04月26日 - 14:56:56

最后更新:2022年05月07日 - 17:54:04

原始链接:https://pabebezz.github.io/article/6cb05388/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%