本文是學習《The Swift Programming Language》整理的相關隨筆,基本的語法不作介紹,主要介紹Swift中的一些特性或者與OC差異點宏怔。
系列文章:
- Swift4 基礎部分:The Basics
- Swift4 基礎部分:Basic Operators
- Swift4 基礎部分:Strings and Characters
- Swift4 基礎部分:Collection Types
- Swift4 基礎部分:Control Flow
- Swift4 基礎部分:Functions
- Swift4 基礎部分:Closures
- Swift4 基礎部分: Enumerations
- Swift4 基礎部分: Classes and Structures
- Swift4 基礎部分: Properties
- Swift4 基礎部分: Methods
- Swift4 基礎部分: Subscripts
- Swift4 基礎部分: Inheritance
- Swift4 基礎部分: Initialization
- Swift4 基礎部分: Deinitialization
Swift uses Automatic Reference Counting (ARC) to track and
manage your app’s memory usage. In most cases, this means
that memory management “just works” in Swift, and you do
not need to think about memory management yourself. ARC
automatically frees up the memory used by class instances
when those instances are no longer needed.
- Swift中是引用自動引用計數(shù)來處理app中的內(nèi)存占用愉豺。也就是說你不需要去考慮app中的內(nèi)存的管理。當類的實例不再被使用時隙袁,ARC會自動釋放其占用的內(nèi)存。
Reference counting only applies to instances of classes.
Structures and enumerations are value types, not reference
types, and are not stored and passed by reference.
- 引用計數(shù)僅僅應用于類的實例弃榨。結(jié)構(gòu)體和枚舉類型是值類型菩收,不是引用類型,也不是通過引用的方式存儲和傳遞鲸睛。
ARC的工作機制(How ARC Works)
Every time you create a new instance of a class, ARC
allocates a chunk of memory to store information about
that instance. This memory holds information about the
type of the instance, together with the values of any
stored properties associated with that instance.
Additionally, when an instance is no longer needed, ARC
frees up the memory used by that instance so that the
memory can be used for other purposes instead. This
ensures that class instances do not take up space in
memory when they are no longer needed.
- 當你每次創(chuàng)建一個類的新的實例的時候娜饵,ARC 會分配一大塊內(nèi)存用來儲存實例的信息。內(nèi)存中會包含實例的類型信息官辈,以及這個實例所有相關屬性的值箱舞。此外遍坟,當實例不再被使用時,ARC會釋放實例所占用的內(nèi)存晴股,并讓釋放的內(nèi)存其他使用愿伴。這就確保了不再被使用的實例,不會一直占用內(nèi)存空間电湘。
ARC的實踐(ARC in Action)
例子:
class Person {
let name:String;
init(name: String){
self.name = name;
print("\(name) is being initialized");
}
deinit {
print("\(name) is being deinitialized");
}
}
var reference1: Person? = Person(name:"xz");
var reference2: Person? = reference1;
var reference3: Person? = reference1;
reference1 = nil;
reference2 = nil;
reference3 = nil;
執(zhí)行結(jié)果:
xz is being initialized
xz is being deinitialized
類實例之間的循環(huán)強引用(Strong Reference Cycles Between Class Instances)
循環(huán)引用在OC中也是常見的公般,直接看一個例子:
class Person {
let name: String;
init(name: String) { self.name = name; }
var apartment: Apartment?;
deinit { print("\(name) is being deinitialized"); }
}
class Apartment {
let unit: String;
init(unit: String) { self.unit = unit; }
var tenant: Person?;
deinit { print("Apartment \(unit) is being deinitialized"); }
}
var john: Person?;
var unit4A: Apartment?;
john = Person(name: "John Appleseed");
unit4A = Apartment(unit: "4A");
// 以下是核心引發(fā)的例子
john!.apartment = unit4A;
unit4A!.tenant = john;
john = nil;
unit4A = nil;
解決類實例之間的強循環(huán)引用(Resolving Strong Reference Cycles Between Class Instances)
Swift provides two ways to resolve strong reference cycles
when you work with properties of class type: weak
references and unowned references.
- Swift 提供了兩種辦法用來解決你在使用類的屬性時所遇到的循環(huán)強引用問題:弱引用(weak reference)和無主引用(unowned reference)。
弱引用(Weak References)
A weak reference is a reference that does not keep a
strong hold on the instance it refers to, and so does not
stop ARC from disposing of the referenced instance. This
behavior prevents the reference from becoming part of a
strong reference cycle. You indicate a weak reference by
placing the weak keyword before a property or variable
declaration.
- 弱引用不會牢牢保持住引用的實例胡桨,并且不會阻止 ARC 銷毀被引用的實例官帘。這種行為阻止了引用變?yōu)檠h(huán)強引用。聲明屬性或者變量時昧谊,在前面加上weak關鍵字表明這是一個弱引用刽虹。
直接改寫一下上述的例子:
class Apartment {
let unit: String;
init(unit: String) { self.unit = unit; }
weak var tenant: Person?; // 注意此處
deinit { print("Apartment \(unit) is being deinitialized"); }
}
執(zhí)行結(jié)果:
John Appleseed is being deinitialized
Apartment 4A is being deinitialized
無主引用(Unowned References)
Like a weak reference, an unowned reference does not keep
a strong hold on the instance it refers to. Unlike a weak
reference, however, an unowned reference is used when the
other instance has the same lifetime or a longer lifetime.
You indicate an unowned reference by placing the unowned
keyword before a property or variable declaration.
- 和弱引用類似,無主引用不會牢牢保持住引用的實例呢诬。和弱引用不同的是涌哲,無主引用擁有同樣或者更長的生命周期相對其他的實例。
An unowned reference is expected to always have a value.
As a result, ARC never sets an unowned reference’s value
to nil, which means that unowned references are defined
using nonoptional types.
- 無主引用一直都是有值的尚镰,ARC無法在實例被銷毀后將無主引用設為nil阀圾,也就是說無主引用是非可選型的。
例子:
class Customer {
let name: String;
var card: CreditCard?;
init(name: String) {
self.name = name;
}
deinit { print("\(name) is being deinitialized"); }
}
class CreditCard {
let number: Int;
unowned let customer: Customer;
init(number: Int, customer: Customer) {
self.number = number;
self.customer = customer;
}
deinit { print("Card #\(number) is being deinitialized"); }
}
var john: Customer?;
john = Customer(name: "John Appleseed");
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!);
john = nil;
執(zhí)行結(jié)果:
John Appleseed is being deinitialized
Card #1234567890123456 is being deinitialized
無主引用以及隱式解析可選屬性(Unowned References and Implicitly Unwrapped Optional Properties)
當相互引用的屬性都不允許為nil時狗唉,此時就需要使用無主引用+隱式解析可選屬性初烘。
例子:
class Country {
let name: String;
var capitalCity: City!;
init(name: String, capitalName: String) {
self.name = name;
self.capitalCity = City(name: capitalName, country: self);
}
}
class City {
let name: String;
unowned let country: Country;
init(name: String, country: Country) {
self.name = name;
self.country = country;
}
}
var country = Country(name: "Canada", capitalName: "Ottawa");
print("\(country.name)'s capital city is called \(country.capitalCity.name)");
執(zhí)行結(jié)果:
Canada's capital city is called Ottawa
閉包中的循環(huán)強引用(Strong Reference Cycles for Closures)
與OC中的block引起的循環(huán)強引用一致,直接看一下例子:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world");
print(paragraph!.asHTML());
paragraph = nil;
執(zhí)行結(jié)果:
<p>hello, world</p>
疑問:
- 為什么
deinit
函數(shù)沒有執(zhí)行分俯? 因為asHTML
的閉包"捕獲"了self,同時asHTML
的屬性持有了閉包的強引用肾筐。二者之間產(chǎn)生了循環(huán)強引用。
解決閉包引起的循環(huán)強引用(Resolving Strong Reference Cycles for Closures)
You resolve a strong reference cycle between a closure and a
class instance by defining a capture list as part of the
closure’s definition.
- 為解決閉包和類實例之間的循環(huán)強引用缸剪,可以定義閉包時同時定義捕獲列表作為閉包的一部分吗铐。
具體捕獲列表的語法參考如下:
lazy var someClosure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
// closure body goes here
}
Define a capture in a closure as an unowned reference when the
closure and the instance it captures will always refer to each
other, and will always be deallocated at the same time.
Conversely, define a capture as a weak reference when the
captured reference may become nil at some point in the future.
- 將閉包內(nèi)的捕獲定義為無主引用,當閉包和捕獲的實例總是互相引用時并且總是同時銷毀時。相反的杏节,將閉包內(nèi)的捕獲定義為弱引用唬渗,當捕獲引用有時可能會是nil時。
上述的例子中奋渔,顯然無主引用
可以解決上述閉包引起的循環(huán)強引用問題镊逝,具體代碼如下:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
[unowned self] () ->String in // 可簡寫為[unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world");
print(paragraph!.asHTML());
paragraph = nil;
執(zhí)行結(jié)果:
<p>hello, world</p>
p is being deinitialized