Swift更加安全,它是類型安全的語言。
Swift容易閱讀,語法和文件結構簡易化。
Swift更易於維護,文件分離後結構更清晰。
Swift代碼更少,簡潔的語法,可以省去大量冗餘代碼
Swift速度更快,運算性能更高
值類型在傳遞和賦值時將進行複製; 賦值給var、let或者給函數傳參,是直接將所有內容拷貝一份, 類似於對文件進行copy、paste操作,產生了全新的文件副本。屬於深拷貝(deep copy)
值類型: 比如結構體,枚舉,是在棧空間上存儲和操作的
引用類型只會使用引用對象的一個"指向"; 賦值給var、let或者給函數傳參,是將內存地址拷貝一份,類似於製作一個文件的替身(快捷方式、連結),指向的是同一個文件。屬於淺拷貝(shallow copy)
引用類型: 比如 Class,是在堆空間上存儲和操作的
class 和 struct 比較,優缺點?class 有以下功能,struct 是沒有的:*class可以繼承,子類可以使用父類的特性和方法
類型轉換可以在運行時檢查和解釋一個實例對象
class可以用 deinit來釋放資源
一個類可以被多次引用
結構較小,適用於複製操作,相比較一個class 實例被多次引用,struct 更安全
無需擔心內存洩露問題
Swift 中,什麼可選型(Optional)在 Swift 中,可選型是為了表達一個變量為空的情況,當一個變量為空,他的值就是 nil
在類型名稱後面加個問號? 來定義一個可選型
值類型或者引用類型都可以是可選型變量
var name: String? // 默認為 nil
var age: Int? // 默認為nil
print(name, age) // 列印 nil, nil
泛型主要是為增加代碼的靈活性而生的,它可以是對應的代碼滿足任意類型的的變量或方法;
泛型可以將類型參數化,提高代碼復用率,減少代碼量
// 實現一個方法,可以交換實現任意類型
func swap<T>(a: inout T, b: inout T) {
(a, b) = (b, a)
}
open: 具備最高訪問權限,其修飾的類可以和方法,可以在任意 模塊中被訪問和重寫.
public: 權限僅次於 open,和 open 唯一的區別是: 不允許其他模塊進行繼承、重寫
internal: 默認權限, 只允許在當前的模塊中訪問,可以繼承和重寫,不允許在其他模塊中訪問
fileprivate: 修飾的對象只允許在當前的文件中訪問;
private: 最低級別訪問權限,只允許在定義的作用域內訪問
關鍵字:Strong,Weak,Unowned 區別?Swift 的內存管理機制同OC一致,都是ARC管理機制; Strong,和 Weak用法同OC一樣
Unowned(無主引用), 不會產生強引用,實例銷毀後仍然存儲著實例的內存地址(類似於OC中的unsafe_unretained), 試圖在實例銷毀後訪問無主引用,會產生運行時錯誤(野指針)
為了提升性能,Struct, String、Array、Dictionary、Set採取了Copy On Write的技術
比如僅當有「寫」操作時,才會真正執行拷貝操作
對於標準庫值類型的賦值操作,Swift 能確保最佳性能,所有沒必要為了保證最佳性能來避免賦值
var title: String {
willSet {
print("willSet", newValue)
}
didSet {
print("didSet", oldValue, title)
}
}
@objc protocol someProtocol {
@objc optional func test()
}
protocol someProtocol {
func test()
}
extension someProtocol{
func test() {
print("test")
}
}
Swift 和OC中的 protocol相同點在於: 兩者都可以被用作代理;
不同點: Swift中的 protocol還可以對接口進行抽象,可以實現面向協議,從而大大提高編程效率,Swift中的protocol可以用於值類型,結構體,枚舉;
[obj iskinOfClass:[SomeClass class]]
[obj isMemberOfClass:[SomeClass class]]
函數重載是指: 函數名稱相同,函數的參數個數不同, 或者參數類型不同,或參數標籤不同, 返回值類型與函數重載無關
swift 支持函數重載
// 關聯值
enum Date {
case digit(year: Int, month: Int, day: Int)
case string(String)
}
// 原始值
enum Grade: String {
case perfect = "A"
case great = "B"
case good = "C"
case bad = "D"
}
{
(參數列表) -> 返回值類型 in 函數體代碼
}
將一個很長的閉包表達式作為函數的最後一個實參
使用尾隨閉包可以增強函數的可讀性
尾隨閉包是一個被書寫在函數調用括號外面(後面)的閉包表達式
// fn 就是一個尾隨閉包參數
func exec(v1: Int, v2: Int, fn: (Int, Int) -> Int) {
print(fn(v1, v2))
}
// 調用
exec(v1: 10, v2: 20) {
$0 + $1
}
非逃逸閉包、逃逸閉包,一般都是當做參數傳遞給函數
非逃逸閉包:閉包調用發生在函數結束前,閉包調用在函數作用域內
逃逸閉包:閉包有可能在函數結束後調用,閉包調用逃離了函數的作用域,需要通過@escaping聲明
// 定義一個數組用於存儲閉包類型
var completionHandlers: [() -> Void] = []
// 在方法中將閉包當做實際參數,存儲到外部變量中
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
func getFirstPositive(_ v1: Int, _ v2: @autoclosure () -> Int) -> Int? {
return v1 > 0 ? v1 : v2()
}
getFirstPositive(10, 20)
為了避免與期望衝突,使用了@autoclosure的地方最好明確注釋清楚:這個值會被推遲執行
@autoclosure 會自動將 20 封裝成閉包 { 20 }
@autoclosure 只支持 () -> T 格式的參數
@autoclosure 並非只支持最後1個參數
有@autoclosure、無@autoclosure,構成了函數重載
如果你想要自動閉包允許逃逸,就同時使用 @autoclosure 和 @escaping 標誌。類似於成員變量這個概念
存儲在實例對象的內存中
結構體、類可以定義存儲屬性
枚舉不可以定義存儲屬性
本質就是方法(函數)
不佔用實例對象的內存
枚舉、結構體、類都可以定義計算屬性
struct Circle {
// 存儲屬性
var radius: Double
// 計算屬性
var diameter: Double {
set {
radius = newValue / 2
}
get {
return radius * 2
}
}
}
lazy屬性必須是var,不能是let
如果多條線程同時第一次訪問lazy屬性
class PhotoView {
// 延遲存儲屬性
lazy var image: Image = {
let url = "https://...x.png"
let data = Data(url: url)
return Image(data: data)
}()
}
struct Circle {
var radius: Double {
willSet {
print("willSet", newValue)
}
didSet {
print("didSet", oldValue, radius)
}
}
init() {
self.radius = 1.0
print("Circle init!")
}
}
嚴格來說,屬性可以分為
實例屬性(Instance Property): 只能通過實例對象去訪問
類型屬性(Type Property):只能通過類型去訪問
可以通過static定義類型屬性 p如果是類,也可以用關鍵字class
struct Car {
static var count: Int = 0
init() {
Car.count += 1
}
}
不同於存儲實例屬性,你必須給存儲類型屬性設定初始值
存儲類型屬性默認就是lazy,會在第一次使用的時候才初始化
就算被多個線程同時訪問,保證只會初始化一次
存儲類型屬性可以是let
枚舉類型也可以定義類型屬性(存儲類型屬性、計算類型屬性)
public class FileManager {
public static let shared = {
// ....
// ....
return FileManager()
}()
private init() { }
}
class Point {
var x = 0.0, y = 0.0
subscript(index: Int) -> Double {
set {
if index == 0 {
x = newValue
} else if index == 1 {
y = newValue }
}
get {
if index == 0 {
return x
} else if index == 1 {
return y
}
return 0
}
}
}
var p = Point()
// 下標賦值
p[0] = 11.1
p[1] = 22.2
// 下標訪問
print(p.x) // 11.1
print(p.y) // 22.2
// 指定初始化器
init(parameters) {
statements
}
// 便捷初始化器
convenience init(parameters) {
statements
}
指定初始化器必須從它的直系父類調用指定初始化器
便捷初始化器必須從相同的類裡調用另一個初始化器
便捷初始化器最終必須調用一個指定初始化器
struct Point {
var x: Int
var y: Int
// 重載運算符
static func + (p1: Point, p2: Point) -> Point {
return Point(x: p1.x + p2.x, y: p1.y + p2.y)
}
}
var p1 = Point(x: 10, y: 10)
var p2 = Point(x: 20, y: 20)
var p3 = p1 + p2
在看點這裡好文分享給更多人↓↓