標籤:role hex user c記憶體 自動 target undle elf 訊息
這是跟在上一篇博文後續內容:
——Core Foundation
架構
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類型之間的轉換樣本:
import CoreFoundation
import Foundation
var cfstr1: CFString = "Hello,World" //建立CFString字串
var str: String = cfstr1 as String //將CFString字串轉換為Swift原生字串Stringvar cfstr2: CFString = str //將Swift原生字串String轉換為CFString字串
這個轉換過程中Core Foundation類型轉換為Swift原生類型是需要強制類型轉換的。
——Core Foundation
架構之記憶體管理
在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對象就記憶體就可以釋放了。
來總結一下:
- 誰建立或拷貝對象,他也一定要負責調用NSObject對象release或autorelease方法,使引用計數減1,中調用者A在第①步,負責建立了NSObject對象,那麼調用者A也必須是負責使引用計數減1,見第④步。
- 誰調用retain方法使引用計數加1,它也一定要負責調用NSObject對象release或autorelease方法,使引用計數減1,中調用者B在第②步,調用者B調用NSObject對象retain方法使引用計數加1,那麼調用者B也必須是負責使引用計數減1,見第⑤步。
對象所有權
一個對象可以有一個或多個所有者,從所有者的角度看是對這個對象具有了“所有權”,從中看,調用者A和調用者B是所有者,他們可能是一段程式,可能是一個對象。他們對NSObject對象具有所有權,不再使用時候他們應該負責放棄對象所有權,當對象沒有所有者時,引用計數為0,它才可以被釋放。
如如果按照對象所有權解釋:調用者A建立或拷貝NSObject對象,這時調用者A就具有了NSObject對象的所有權,見第①步。調用者B調用NSObject對象retain方法,就獲得了也NSObject對象的所有權,見第②步。調用者A調用NSObject對象release方法,放棄NSObject對象的所有權,見第③步。調用者C只是使用NSObject對象沒有獲得NSObject對象的所有權,見第④步。調用者B調用NSObject對象release方法,放棄NSObject對象的所有權,見第⑤步,但是調用者B使用這個NSObject對象過程中,由於其他調用者放棄所有權,導致NSObject對象被釋放,那麼調用者B中程式就會發生運行期錯誤。
——Core Foundation
架構之記憶體託管對象與非託管對象
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) -> Unmanaged<CFHost> //記憶體非託管對象
·記憶體非託管對象
記憶體非託管對象就是記憶體需要程式員自己管理。這是由於在獲得對象的方法中沒有使用CF_RETURNS_RETAINED或CF_RETURNS_NOT_RETAINED注釋聲明,編譯器無法協助管理記憶體。在具體使用時候我們可以上一節的方法判斷是否為非記憶體託管對象。
記憶體非託管對象使用起來有些麻煩,要根據獲得所有權方法,進行相應的處理。
- 如果一個函數名中包含Create或Copy,則調用者獲得這個對象的同時也獲得對象所有權,傳回值Unmanaged<T>需要調用takeRetainedValue()方法獲得對象。調用者不再使用對象時候,Swift代碼中需要調用CFRelease函數放棄對象所有權,這是因為Swift是ARC記憶體管理的。
- 如果一個函數名中包含Get,則調用者獲得這個對象的同時不會獲得對象所有權,傳回值Unmanaged<T>需要調用takeUnretainedValue()方法獲得對象。
——Cocoa Touch
設計模式及應用之單例模式
什麼是設計模式。設計模式是在特定情境下對特定問題的解決方案,這些解決方案是經過反覆論證和測試總結出來的。實際上,除了軟體設計,設計模式也被廣泛應用於其他領域,比如UI設計和建築設計等。
下面來介紹Cocoa Touch架構中的設計模式中的單例模式。
單例模式
單例模式的作用是解決“應用中只有一個執行個體”的一類問題。在Cocoa Touch架構中,有UIApplication、NSUserDefaults和NSNotificationCenter等單例類。另外,NSFileManager和NSBundle類雖然屬於Cocoa架構的內容,但也可以在Cocoa Touch架構中使用(Cocoa架構中的單例類有NSFileManager、NSWorkspace和NSApplication等)。
問題提出
在一個應用程式的生命週期中,有時候只需要某個類的一個執行個體。例如:當iOS應用程式啟動時,應用的狀態由UIApplication類的一個執行個體維護,這個執行個體代表了整個“應用程式物件”,它只能是一個執行個體,其作用是共用應用程式中的一些資源、控制應用程式的訪問,以及保持應用程式的狀態等。
解決方案
單例模式的實現有很多方案,蘋果公司在《Using Swift with Cocoa andObjective-C》官方文檔中給出了一種單例模式的實現。最簡單形式代碼如下:
class Singleton {
static letsharedInstance = Singleton()
}
上述代碼採用static的類屬性實現單例模式,這種類屬性只被消極式載入執行一次,即便是在多線程情況下也只是執行一次,並且保證是安全執行緒的。
如果需要進行一些初始化,可以使用如下帶有閉包形式代碼:
class Singleton {
static letsharedInstance: Singleton = {
letinstance = Singleton()
// 初始化處理
returninstance
}()
}
——Cocoa Touch
設計模式及應用之目標與動作
目標(Target)與動作(Action)是iOS和OS X應用開發的中事件處理機制。
要實現目標與動作的串連有兩種方式:Interface Builder連線實現和編程實現。
- Interface Builder連線實現
Interface Builder連線實現就是故事板或Xib檔案中,通過連線而現實。
- 編程實現
編程實現是通過UIControl類addTarget(_:action:forControlEvents:)方法實現的,主要代碼如下:
class ViewController: UIViewController {
override func viewDidLoad(){
super.viewDidLoad()
self.view.backgroundColor= UIColor.whiteColor()
let screen = UIScreen.mainScreen().bounds;
let labelWidth:CGFloat= 90
letlabelHeight:CGFloat = 20
letlabelTopView: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)
letbuttonWidth:CGFloat = 60
letbuttonHeight:CGFloat = 20
letbuttonTopView: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("OKButton onClick.")
}
...
}
上述代碼中建立並設定UIButton對象,其中建立UIButton對象,參數type是設定按鈕的樣式,UIButton樣式:
- Custom。自訂類型。如果不喜歡圓角按鈕,可以使用該類型。
- System。系統預設屬性,表示該按鈕沒有邊框,在iOS 7之前按鈕預設為圓角矩形。
- Detail Disclosure。細節展示按鈕,主要用於表視圖中的細節展示。
- Info Light和Info Dark。這兩個是資訊按鈕,樣式上與細節展示按鈕一樣,表示有一些資訊需要展示,或有可以設定的內容。
- Add Contact。新增連絡人...按鈕
- 代碼調用addTarget(_:action:forControlEvents:)方法,方法第一個參數是target,即事件處理對象,本例中是self;方法第二個參數是action,即事件處理對象中的方法,
代碼中是"onClick:",方法第三個參數是事件,TouchUpInside事件是按鈕的觸摸點擊事件。
如果調用如下無參數方法:
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表示第二個參數的外部參數名。
——Cocoa Touch
設計模式及應用之選取器
實現目標與動作關聯使用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(extSendersender: 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 funconClick(sender: AnyObject) {
NSLog("onClick:")
}
——Cocoa Touch
設計模式及應用之通知機制
通知(Notification)機制是基於觀察者(Observer)模式也叫發布/訂閱(Publish/Subscribe)模式,是 MVC( 模型-視圖-控制器)模式的重要組成部分。
在軟體系統中,一個對象狀態改變也會連帶影響其他很多個物件的狀態發生改變。能夠實現這一需求的設計方案有很多,但能夠做到複用性強且對象之間匿名通訊的,觀察者模式是其中最為適合的一個。
通知機制可以實現“一對多”的對象之間的通訊。,在通知機制中對某個通知感興趣的所有對象都可以成為接收者。首先,這些對象需要向通知中樞(NSNotificationCenter)發出addObserver訊息進行註冊通知,在投送對象通過postNotificationName訊息投送通知給通知中樞,通知中樞就會把通知廣播給註冊過的接收者。所有的接收者都不知道通知是誰投送的,更不關心它的細節。投送對象與接收者是一對多的關係。接收者如果對通知不再關注,會給通知中樞發出removeObserver訊息登出通知,以後不再接收通知。
——Cocoa Touch
設計模式及應用之MVC模式
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是視圖和控制項的根類。
——Cocoa Touch
設計模式及應用之響應者鏈與觸摸事件
應用與使用者進行互動,依賴於各種各樣的事件。事件響應者對象是可以響應事件並對其進行處理的對象,響應者鏈是由一系列連結在一起的響應者組成的。響應者鏈在事件處理中是非常重要的,響應者鏈可以把用
戶事件路由給正確的對象。
響應者對象與響應鏈
UIResponder是所有響應者對象的基類,它不僅為事件處理,而且也為常見的響應者行為定義編程介面。UIApplication、UIView(及其子類,包括UIWindow)和UIViewController(及其子類)都直接或間接地繼承自UIResponder類。
第一響應者是應用程式中當前負責接收觸摸事件的響應者對象(通常是一個UIView對象)。UIWindow對象以訊息的形式將事件發送給第一響應者,使其有機會首先處理事件。如果第一響應者沒有進行處理,系統就將事件(通過訊息)傳遞給響應者鏈中的下一個響應者,看看它是否可以進行處理。
響應者鏈是一系列連結在一起的響應者對象,它允許響應者對象將處理事件的責任傳遞給其他更進階別的對象。隨著應用程式尋找能夠處理事件的對象,事件就在響應者鏈中向上傳遞。響應者鏈由一系列“下一個響應者”組成。
1.第一響應者將事件傳遞給它的視圖控制器(如果有的話),然後是它的父視圖。
2.類似地,視圖層次中的每個後續視圖都首先傳遞給它的視圖控制器(如果有的話),然後是它的父視圖。
3.最上層的[內容] 檢視將事件傳遞給UIWindow對象。
4.UIWindow對象將事件傳遞給UIApplication單例對象。
觸摸事件
觸摸(UITouch)對象表示螢幕上的一個觸摸事件,訪問觸摸是通過UIEvent對象傳遞給事件響應者對象的。觸摸對象有時間和空間兩方面。
1.時間方面
時間方面資訊稱為階段(phase),表示觸摸是否剛剛開始、是否正在移動或處於靜止狀態,以及何時結束,也就是手指何時從螢幕抬起。
在給定的觸摸階段中,如果發生新的觸摸動作或已有的觸摸動作發生變化,則應用程式就會發送這些訊息。
- 當一個或多個手指觸碰螢幕時,發送touchesBegan:withEvent:訊息。
- 當一個或多個手指在螢幕上移動時,發送touchesMoved:withEvent:訊息。
- 當一個或多個手指離開螢幕時,發送touchesEnded:withEvent:訊息。
2.空間方面
觸摸點對象還包括當前在視圖或視窗中的位置資訊,以及之前的位置資訊(如果有的話)。下面的方法是可以獲得觸摸點所在視窗或視圖中的位置。
func locationInView(_view: UIView?) -> CGPoint
獲得前一個觸摸點所在視窗或視圖中的位置資訊:
func previousLocationInView(_ view: UIView?) -> CGPoint
——Swift
與Objective-C混合編程之語言
在Swift語言出現之前,開發iOS或OS X應用主要使用Objective-C語言,此外還可以使用C和C++語言,但是UI部分只能使用Objective-C語言。
選擇語言
Swift語言出現後,蘋果公司給程式員提供了更多的選擇,讓這兩種語言並存。既然是並存,我們就有4種方式可以選擇:
- 採用純Swift的改革派方式;
- 採用純Objective-C的保守派方式;
- 採用Swift調用Objective-C的左傾改良派方式;
- 採用Objective-C調用Swift的右傾改良派方式。
副檔名
在Xcode等工具開發iOS或OS X應用可以編寫多種形式的源檔案,原本就可以使用Objective-C、C和C++語言,Swift語言出現後源檔案的形式更加多樣。可能的副檔名說明:
——Swift
與Objective-C混合編程之Swift與Objective-C API映射Swift與Objective-C API映射
在混合編程過程中Swift與Objective-C調用是雙向的,由於不同語言對於相同API的表述是不同的,他們之間是有某種映射規律的,這種API映射規律主要體現在建構函式和方法兩個方面。
1、建構函式映射
在Swift與Objective-C語言進行混合編程時,首先涉及到調用建構函式執行個體化對象問題,不同語言下構造函數表述形式不同,是蘋果公司官方API文檔,描述了NSString類的一個建構函式。
Swift建構函式除了第一個參數外,其它參數的外部名就是選取器對應部分名。規律的其它細節圖中已經解釋的很清楚了,這個規律反之亦然,這裡不再贅述。
2、方法名映射
在Swift與Objective-C語言進行混合編程時,不同語言下方法名表述形式也是不同的,是蘋果公司官方API文檔,描述了NSString類的rangeOfString:options:range:方法。
選取器第一個部分rangeOfString作為方法名,一般情況下Swift方法第一個參數的外部參數名是要省略的,“_”符號表示省略。之後的選取器各部分名(如:options和range),作為外部參數名。除了參數名對應為,參數類型也要對應下來。
Swift2.0之後方法可以聲明拋出錯誤,這些能拋出錯誤的方法,不同語言下方法名表述形式所示,是writeToFile:atomically:encoding:error:蘋果公司官方API文檔。
比較兩種不同語言,我們會發現error參數在Swift語言中不再使用,而是在方法後添加了throws關鍵字。
這種映射規律不僅僅只適用於蘋果公司官方提供的Objective-C類,也適用於自己編寫的Objective-C類。
——Swift
與C/C++混合編程之資料類型映射
如果引入必要的標頭檔,在Objective-C語言中可以使用C資料類型。而在Swift語言中是不能直接使用C資料類型,蘋果公司為Swift語言提供與C語言相對應資料類型。這些類型主要包括:C語言基礎資料型別 (Elementary Data Type)和指標類型。
如表所述是Swift資料類型與C語言基礎資料型別 (Elementary Data Type)對應關係表。
Swift語言中的這些資料類型與Swift原生的資料類型一樣,本質上都是結構體類型。
如表所述是Swift資料類型與C語言指標資料類型對應關係表。
從表可見針對C語言多樣的指標形式,Swift主要通過提供了三種不安全的泛型指標類型:UnsafePointer<T>、UnsafeMutablePointer<T>和AutoreleasingUnsafeMutablePointer<T>。T是泛型預留位置,表示不同的資料類型。另外,還有COpaquePointer類型是Swift中無法表示的C指標類型。
下面我們分別介紹一下。
- UnsafePointer<T>
UnsafePointer<T>是一個比較常用的常量指標類型,這種指標對象需要程式員自己手動管理記憶體,即需要自己申請和釋放記憶體。它一般是由其他的指標建立。它的主要的建構函式有:
· init( other: COpaquePointer)。通過COpaquePointer類型指標建立。
· init<U>( from: UnsafeMutablePointer<U>)。通過 UnsafeMutablePointer類型指標建立。
· init<U>(_ from: UnsafePointer<U>)。通過UnsafePointer類型指標建立。
UnsafePointer<T>主要的屬性:
· memory。唯讀屬性,它能夠訪問指標指向的內容。
UnsafePointer<T>主要的方法:
· successor() -> UnsafePointer<T>。獲得指標指向的下一個記憶體位址的內容。
· predecessor() -> UnsafePointer<T>。獲得指標指向的上一個記憶體位址的內容。
- UnsafeMutablePointer<T>
UnsafeMutablePointer<T>是一個比較常用的可變指標類型,這種指標對象需要程式員自己手動管理記憶體,自己負責申請和釋放記憶體。可變指標可以由其他的指標建立,也可以可變指標通過alloc(:)方法申請記憶體空間,再調用initialize(:)方法初始化指標指向數值。當指標對象釋放時候需要調用destroy()方法銷毀指標指向對象,它是initialize(:)方法的反向操作,他們兩個方法在代碼中應該成對出現的。最後還要調用dealloc(:)方法釋放指標指向的記憶體空間,它是alloc(_:)方法的反向操作,這兩個方法在代碼中也應該成對出現。
- AutoreleasingUnsafeMutablePointer<T>
AutoreleasingUnsafeMutablePointer<T>被稱為自動釋放指標,在方法或函數中聲明為該類型的參數,是輸入輸出類型的,在調用方法或函數過程中,參數先首先被拷貝到一個無所有權的緩衝區,在方法或函數內使用的這個緩衝區,當方法或函數返回時,緩衝區資料重新寫回到參數。
這是我在學Swift整理的基礎筆記,希望給更多剛學IOS開發人員帶來協助,在這裡博主非常感謝大家的支援!
到這裡就基本完成了Swift語言基礎筆記整理了。 如果大家覺得此博文對您有協助,那就動動你的小手指點個贊!! 哈哈,感謝各位博友的支援!!!
從0開始學Swift筆記整理(五)