這是跟在上一篇博文後續內容:程序員
Core Foundation框架是蘋果公司提供一套概念來源於Foundation框架,編程接口面向C語言風格的API。雖然在Swift中調用這種C語言風格的API比較麻煩,可是在OS X和iOS開發過程當中,有時候使用Core Foundation框架的API是很是方便的,例如在與C語言混合編碼的時候。
Core Foundation框架與Foundation框架緊密相關,他們具備與相同的接口,可是不一樣。Core Foundation框架是基於C語言風格的,而Foundation框架是基於Objective-C語言風格的。在OS X和iOS程序代碼中常常會有多種語言風格的代碼混合在一塊兒的狀況,這使得咱們開發變得更加麻煩。
數據類型映射
Core Foundation框架提供了一些不透明的數據類型,這些數據類型封裝了一些數據和操做,他們也能夠稱爲「類」,他們都繼承於CFType類,CFType是所用Core Foundation框架類型的根類。這些數據類型在Foundation框架中都有相應的數據類型與之對應,這些數據類型也有一些與Swift原生數據類型有對應關係。
編程
看看Swift原生類型與Core Foundation類型之間的轉換示例:設計模式
importCoreFoundationimportFoundationvarCFString"Hello,World"//建立CFString字符串varStringasString//將CFString字符串轉換爲Swift原生字符串StringvarCFString//將Swift原生字符串String轉換爲CFString字符串
cfstr1:=
str:= cfstr1 cfstr2:= str
這個轉換過程當中Core Foundation類型轉換爲Swift原生類型是須要強制類型轉換的。安全
在Swift原生數據類型、Foundation框架數據類型和Core Foundation框架數據類型之間轉換過程當中,雖然是大部分是能夠零開銷橋接,零開銷並不意味着內存什麼都不用管。Swift類型內存管理是採用ARC,Foundation類型和Core Foundation類型內存管理都是採用MRC或ARC,Core Foundation類型內存管理是基於C語言風格的,它有一個對象全部權的概念。
Objective-C的MRC內存管理
Core Foundation的內存管理與Objective-C的MRC內存管理密不可分,先介紹一下Objective-C的MRC內存管理。
全部Objective-C類都繼承NSObject類,每一個NSObject對象都有一個內部計數器,這個計數器跟蹤對象的引用次數,被稱爲「引用計數」(Reference Count,簡稱RC)。當對象被建立時候,引用計數爲1。爲了保證對象的存在,能夠調用retain方法保持對象,retain方法會使其引用計數加1,若是不須要這個對象能夠調用release或autorelease方法,release或autorelease方法使其引用計數減1。當對象的引用計數爲0的時候,系統運行環境纔會釋放對象內存。
引用計數示例如圖所示,首先在第①步調用者A中建立了一個NSObject對象,這時該對象引用計數爲1。在第②步調用者B中想使用這個NSObject對象,因而使用NSObject對象引用,可是爲了防止使用過程當中NSObject對象被釋放,能夠調用retain方法使引用計數加1,這時引用計數爲2。在第③步調用者A中調用release或autorelease方法,使引用計數減1,這時引用計數爲1。在第④步調用者C中調用release或autorelease方法,只是得到NSObject對象引用,並無調用retain、release或autorelease方法,所以沒有引發引用計數的變化。在第⑤步調用者B中調用release或autorelease方法使引用計數減1,這時引用計數爲0。這個時候NSObject對象就內存就能夠釋放了。
來總結一下:多線程
Swift中調用Core Foundation函數得到對象時候,對象分爲:內存託管對象和內存非託管對象。閉包
·內存託管對象
內存託管對象就是由編譯器幫助管理內存,咱們不須要調用CFRetain函數得到對象全部權,也不須要調用CFRelease函數放棄對象全部權。
得到這些內存託管對象的方法,是採用了CF_RETURNS_RETAINED或CF_RETURNS_NOT_RETAINED註釋聲明架構
func CFStringCreateWithCString(_ alloc: CFAllocator!,
_ cStr: UnsafePointer<Int8>,
_ encoding: CFStringEncoding)CFString//內存託管對象->!
func CFHostCreateCopy(_ alloc: CFAllocator?,
_ host: CFHost)UnmanagedCFHost//內存非託管對象-><>
·內存非託管對象
內存非託管對象就是內存須要程序員本身管理。這是因爲在得到對象的方法中沒有使用CF_RETURNS_RETAINED或CF_RETURNS_NOT_RETAINED註釋聲明,編譯器沒法幫助管理內存。在具體使用時候咱們能夠上一節的方法判斷是否爲非內存託管對象。
內存非託管對象使用起來有些麻煩,要根據得到全部權方法,進行相應的處理。框架
什麼是設計模式。設計模式是在特定場景下對特定問題的解決方案,這些解決方案是通過反覆論證和測試總結出來的。實際上,除了軟件設計,設計模式也被普遍應用於其餘領域,好比UI設計和建築設計等。
下面來介紹Cocoa Touch框架中的設計模式中的單例模式。
單例模式
單例模式的做用是解決「應用中只有一個實例」的一類問題。在Cocoa Touch框架中,有UIApplication、NSUserDefaults和NSNotificationCenter等單例類。另外,NSFileManager和NSBundle類雖然屬於Cocoa框架的內容,但也能夠在Cocoa Touch框架中使用(Cocoa框架中的單例類有NSFileManager、NSWorkspace和NSApplication等)。
問題提出
在一個應用程序的生命週期中,有時候只須要某個類的一個實例。例如:當iOS應用程序啓動時,應用的狀態由UIApplication類的一個實例維護,這個實例表明了整個「應用程序對象」,它只能是一個實例,其做用是共享應用程序中的一些資源、控制應用程序的訪問,以及保持應用程序的狀態等。
解決方案
單例模式的實現有不少方案,蘋果公司在《Using Swift with Cocoa and Objective-C》官方文檔中給出了一種單例模式的實現。最簡單形式代碼以下:ide
class Singleton {函數
static let sharedInstance = Singleton()
}
上述代碼採用static的類屬性實現單例模式,這種類屬性只被延遲加載執行一次,即使是在多線程狀況下也只是執行一次,而且保證是線程安全的。
若是須要進行一些初始化,可使用以下帶有閉包形式代碼:
class Singleton {
static let sharedInstance: Singleton = {
let instance = Singleton()
// 初始化處理
return instance
}()
}
目標(Target)與動做(Action)是iOS和OS X應用開發的中事件處理機制。
要實現目標與動做的鏈接有兩種方式:Interface Builder連線實現和編程實現。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.whiteColor()
let screen = UIScreen.mainScreen().bounds;
let labelWidth:CGFloat = 90
let labelHeight:CGFloat = 20
let labelTopView:CGFloat = 150
let label = UILabel(frame: CGRectMake((screen.size.width
-labelWidth)/2 , labelTopView, labelWidth, labelHeight))
label.text = "Label"
//字體左右劇中
label.textAlignment = .Center
self.view.addSubview(label)
let button = UIButton(type: UIButtonType.System)// 建立UIButton對象
button.setTitle("OK", forState: UIControlState.Normal)
let buttonWidth:CGFloat = 60
let buttonHeight:CGFloat = 20
let buttonTopView:CGFloat = 240
button.frame = CGRectMake((screen.size.width
- buttonWidth)/2 , buttonTopView, buttonWidth, buttonHeight)
button.addTarget(self, action: "onClick:",
forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button)
}
func onClick(sender: AnyObject) {
NSLog("OK Button onClick.")
}
...
}
上述代碼中建立並設置UIButton對象,其中建立UIButton對象,參數type是設置按鈕的樣式,UIButton樣式:
func onClick() {
}
調用代碼以下:
button.addTarget(self, action: "onClick",
Ê forControlEvents: UIControlEvents.TouchUpInside)
區別在於action參數"onClick"方法名不一樣,action參數方法名的冒號暗示了方法名應該具備幾個參數。若是要調用的方法是以下3個參數形式:
func onClick(sender: AnyObject, forEvent event: UIEvent) {
}
那麼調用代碼以下:
button.addTarget(self, action: "onClick:forEvent:",
Ê forControlEvents: UIControlEvents.TouchUpInside)
其中"onClick:forEvent:"是調用方法名,onClick表示方法名也是,forEvent表示第二個參數的外部參數名。
實現目標與動做關聯使用UIControl類addTarget(_:action:forControlEvents:)方法,示例代碼以下:
button.addTarget(self, action: "onClick:",
forControlEvents: UIControlEvents.TouchUpInside)
其中的action參數"onClick:"事實上就是選擇器(Selector)。
經過選擇器調用方法,關鍵是方法名字,它有必定規律的。窮其根本是源自於Objective-C多重參數方法命名規律。方法名的冒號暗示了方法名應該具備幾個參數,下面咱們看幾個示例:
//選擇器爲"onClick:"
func onClick(sender: AnyObject) {
NSLog("onClick:")
}
//選擇器爲"onClick:forEvent:"
func onClick(sender: AnyObject, forEvent event: UIEvent) {
NSLog("onClick:forEvent:")
}
//選擇器爲"onClickWithExtSender:forEvent:"
func onClick(extSender sender: AnyObject, forEvent event: UIEvent) {
NSLog("onClickWithExtSender:forEvent:")
}
出於數據封裝的須要,咱們會在方法前面加private,使其變爲私有方法,代碼以下。
private func onClick(sender: AnyObject) {
NSLog("onClick:")
}
可是這樣方法在調用時候會出現以下錯誤:
unrecognized selector sent to instance 0x7f7f81499b10'
這個錯誤的意思是沒有找到選擇器所指定的方法,也就是沒有找到onClick:方法。正確的作法是在方法前面添加@objc屬性註釋,這說明選擇器是在objc runtime運行環境下調用的。
//選擇器爲"onClick:"
@objc private func onClick(sender: AnyObject) {
NSLog("onClick:")
}
通知(Notification)機制是基於觀察者(Observer)模式也叫發佈/訂閱(Publish/Subscribe)模式,是 MVC( 模型-視圖-控制器)模式的重要組成部分。
在軟件系統中,一個對象狀態改變也會連帶影響其餘不少對象的狀態發生改變。可以實現這一需求的設計方案有不少,但可以作到複用性強且對象之間匿名通訊的,觀察者模式是其中最爲適合的一個。
通知機制能夠實現「一對多」的對象之間的通訊。如圖所示,在通知機制中對某個通知感興趣的全部對象均可以成爲接收者。首先,這些對象須要向通知中心(NSNotificationCenter)發出addObserver消息進行註冊通知,在投送對象經過postNotificationName消息投送通知給通知中心,通知中心就會把通知廣播給註冊過的接收者。全部的接收者都不知道通知是誰投送的,更不關心它的細節。投送對象與接收者是一對多的關係。接收者若是對通知再也不關注,會給通知中心發出removeObserver消息註銷通知,之後再也不接收通知。
MVC(Model-View-Controller,模型-視圖-控制器)模式是至關古老的設計模式之一,它最先出如今Smalltalk語言中。如今,不少計算機語言和架構都採用了MVC模式。
MVC模式概述
MVC模式是一種複合設計模式,由 「觀察者」(Observer)模式、「策略」(Strategy)模式和「合成」(Composite)模式等組成。MVC模式由3個部分組成,如圖所示,這3個部分的做用以下所示。
· 模型。保存應用數據的狀態,迴應視圖對狀態的查詢,處理應用業務邏輯,完成應用的功能,將狀態的變化通知視圖。
· 視圖。爲用戶展現信息並提供接口。用戶經過視圖向控制器發出動做請求,而後再向模型發出查詢狀態的申請,而模型狀態的變化會通知給視圖。
· 控制器。接收用戶請求,根據請求更新模型。另外,控制器還會更新所選擇的視圖做爲對用戶請求的迴應。控制器是視圖和模型的媒介,能夠下降視圖與模型的耦合度,使視圖和模型的權責更加清晰,從而提升開發效率。
對應於哲學中的「內容」與「形式」, 在MVC模型中,模式是「內容」,它存儲了視圖所須要的數據,視圖是「形式」,是外部表現方式,而控制器是它們的媒介。
Cocoa Touch中的MVC模式
上面咱們討論的是通用的MVC模式,而Cocoa和Cocoa Touch框架中的MVC模式與傳統的MVC模式略有不一樣,前者的模型與視圖不能進行任何通訊,全部的通訊都是經過控制器完成的,如圖所示。
在Cocoa Touch框架的UIKit框架中,UIViewController是全部控制器的根類,如UITableViewController、UITabBarController和UINavigationController。UIView是視圖和控件的根類。
應用與用戶進行交互,依賴於各類各樣的事件。事件響應者對象是能夠響應事件並對其進行處理的對象,響應者鏈是由一系列連接在一塊兒的響應者組成的。響應者鏈在事件處理中是很是重要的,響應者鏈能夠把用
戶事件路由給正確的對象。
響應者對象與響應鏈
UIResponder是全部響應者對象的基類,它不只爲事件處理,並且也爲常見的響應者行爲定義編程接口。UIApplication、UIView(及其子類,包括UIWindow)和UIViewController(及其子類)都直接或間接地繼承自UIResponder類。
第一響應者是應用程序中當前負責接收觸摸事件的響應者對象(一般是一個UIView對象)。UIWindow對象以消息的形式將事件發送給第一響應者,使其有機會首先處理事件。若是第一響應者沒有進行處理,系統就將事件(經過消息)傳遞給響應者鏈中的下一個響應者,看看它是否能夠進行處理。
響應者鏈是一系列連接在一塊兒的響應者對象,它容許響應者對象將處理事件的責任傳遞給其餘更高級別的對象。隨着應用程序尋找可以處理事件的對象,事件就在響應者鏈中向上傳遞。響應者鏈由一系列「下一個響應者」組成。
1.第一響應者將事件傳遞給它的視圖控制器(若是有的話),而後是它的父視圖。
2.相似地,視圖層次中的每一個後續視圖都首先傳遞給它的視圖控制器(若是有的話),而後是它的父視圖。
3.最上層的容器視圖將事件傳遞給UIWindow對象。
4.UIWindow對象將事件傳遞給UIApplication單例對象。
觸摸事件
觸摸(UITouch)對象表示屏幕上的一個觸摸事件,訪問觸摸是經過UIEvent對象傳遞給事件響應者對象的。觸摸對象有時間和空間兩方面。
1.時間方面
時間方面信息稱爲階段(phase),表示觸摸是否剛剛開始、是否正在移動或處於靜止狀態,以及什麼時候結束,也就是手指什麼時候從屏幕擡起。
在給定的觸摸階段中,若是發生新的觸摸動做或已有的觸摸動做發生變化,則應用程序就會發送這些消息。
2.空間方面
觸摸點對象還包括當前在視圖或窗口中的位置信息,以及以前的位置信息(若是有的話)。下面的方法是能夠得到觸摸點所在窗口或視圖中的位置。
func locationInView(_ view: UIView?) -> CGPoint
得到前一個觸摸點所在窗口或視圖中的位置信息:
func previousLocationInView(_ view: UIView?) -> CGPoint
在Swift語言出現以前,開發iOS或OS X應用主要使用Objective-C語言,此外還可使用C和C++語言,可是UI部分只能使用Objective-C語言。
選擇語言
Swift語言出現後,蘋果公司給程序員提供了更多的選擇,讓這兩種語言並存。既然是並存,咱們就有4種方式能夠選擇:
文件擴展名
在Xcode等工具開發iOS或OS X應用能夠編寫多種形式的源文件,本來就可使用Objective-C、C和C++語言,Swift語言出現後源文件的形式更加多樣。可能的文件擴展名說明:
在混合編程過程當中Swift與Objective-C調用是雙向的,因爲不一樣語言對於相同API的表述是不一樣的,他們之間是有某種映射規律的,這種API映射規律主要體如今構造函數和方法兩個方面。
一、構造函數映射
在Swift與Objective-C語言進行混合編程時,首先涉及到調用構造函數實例化對象問題,不一樣語言下構造函數表述形式不一樣,如圖是蘋果公司官方API文檔,描述了NSString類的一個構造函數。
Swift構造函數除了第一個參數外,其它參數的外部名就是選擇器對應部分名。規律的其它細節圖中已經解釋的很清楚了,這個規律反之亦然,這裏再也不贅述。
2、方法名映射
在Swift與Objective-C語言進行混合編程時,不一樣語言下方法名錶述形式也是不一樣的,如圖是蘋果公司官方API文檔,描述了NSString類的rangeOfString:options:range:方法。
選擇器第一個部分rangeOfString做爲方法名,通常狀況下Swift方法第一個參數的外部參數名是要省略的,「_」符號表示省略。以後的選擇器各部分名(如:options和range),做爲外部參數名。除了參數名對應爲,參數類型也要對應下來。
Swift 2.0以後方法能夠聲明拋出錯誤,這些能拋出錯誤的方法,不一樣語言下方法名錶述形式如圖下圖所示,是writeToFile:atomically:encoding:error:蘋果公司官方API文檔。
比較兩種不一樣語言,咱們會發現error參數在Swift語言中再也不使用,而是在方法後添加了throws關鍵字。
這種映射規律不只僅只適用於蘋果公司官方提供的Objective-C類,也適用於本身編寫的Objective-C類。
若是引入必要的頭文件,在Objective-C語言中可使用C數據類型。而在Swift語言中是不能直接使用C數據類型,蘋果公司爲Swift語言提供與C語言相對應數據類型。這些類型主要包括:C語言基本數據類型和指針類型。
如表所述是Swift數據類型與C語言基本數據類型對應關係表。
Swift語言中的這些數據類型與Swift原生的數據類型同樣,本質上都是結構體類型。
如表所述是Swift數據類型與C語言指針數據類型對應關係表。
從表可見針對C語言多樣的指針形式,Swift主要經過提供了三種不安全的泛型指針類型:UnsafePointer<T>、UnsafeMutablePointer<T>和AutoreleasingUnsafeMutablePointer<T>。T是泛型佔位符,表示不一樣的數據類型。另外,還有COpaquePointer類型是Swift中沒法表示的C指針類型。
下面咱們分別介紹一下。