在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ Playground 快速原型制作
與四軸無人機(jī)的通訊
在沙盒中編寫腳本
結(jié)構(gòu)體和值類型
深入理解 CocoaPods
UICollectionView + UIKit 力學(xué)
NSString 與 Unicode
代碼簽名探析
測試
架構(gòu)
第二期-并發(fā)編程
Metal
自定義控件
iOS 中的行為
行為驅(qū)動(dòng)開發(fā)
Collection View 動(dòng)畫
截圖測試
MVVM 介紹
使 Mac 應(yīng)用數(shù)據(jù)腳本化
一個(gè)完整的 Core Data 應(yīng)用
插件
字符串
為 iOS 建立 Travis CI
先進(jìn)的自動(dòng)布局工具箱
動(dòng)畫
為 iOS 7 重新設(shè)計(jì) App
XPC
從 NSURLConnection 到 NSURLSession
Core Data 網(wǎng)絡(luò)應(yīng)用實(shí)例
GPU 加速下的圖像處理
自定義 Core Data 遷移
子類
與調(diào)試器共舞 - LLDB 的華爾茲
圖片格式
并發(fā)編程:API 及挑戰(zhàn)
IP,TCP 和 HTTP
動(dòng)畫解釋
響應(yīng)式 Android 應(yīng)用
初識 TextKit
客戶端
View-Layer 協(xié)作
回到 Mac
Android
Core Image 介紹
自定義 Formatters
Scene Kit
調(diào)試
項(xiàng)目介紹
Swift 的強(qiáng)大之處
測試并發(fā)程序
Android 通知中心
調(diào)試:案例學(xué)習(xí)
從 UIKit 到 AppKit
iOS 7 : 隱藏技巧和變通之道
安全
底層并發(fā) API
消息傳遞機(jī)制
更輕量的 View Controllers
用 SQLite 和 FMDB 替代 Core Data
字符串解析
終身學(xué)習(xí)的一代人
視頻
Playground 快速原型制作
Omni 內(nèi)部
同步數(shù)據(jù)
設(shè)計(jì)優(yōu)雅的移動(dòng)游戲
繪制像素到屏幕上
相機(jī)與照片
音頻 API 一覽
交互式動(dòng)畫
常見的后臺實(shí)踐
糟糕的測試
避免濫用單例
數(shù)據(jù)模型和模型對象
Core Data
字符串本地化
View Controller 轉(zhuǎn)場
照片框架
響應(yīng)式視圖
Square Register 中的擴(kuò)張
DTrace
基礎(chǔ)集合類
視頻工具箱和硬件加速
字符串渲染
讓東西變得不那么糟
游戲中的多點(diǎn)互聯(lián)
iCloud 和 Core Data
Views
虛擬音域 - 聲音設(shè)計(jì)的藝術(shù)
導(dǎo)航應(yīng)用
線程安全類的設(shè)計(jì)
置換測試: Mock, Stub 和其他
Build 工具
KVC 和 KVO
Core Image 和視頻
Android Intents
在 iOS 上捕獲視頻
四軸無人機(jī)項(xiàng)目
Mach-O 可執(zhí)行文件
UI 測試
值對象
活動(dòng)追蹤
依賴注入
Swift
項(xiàng)目管理
整潔的 Table View 代碼
Swift 方法的多面性
為什么今天安全仍然重要
Core Data 概述
Foundation
Swift 的函數(shù)式 API
iOS 7 的多任務(wù)
自定義 Collection View 布局
測試 View Controllers
訪談
收據(jù)驗(yàn)證
數(shù)據(jù)同步
自定義 ViewController 容器轉(zhuǎn)場
游戲
調(diào)試核對清單
View Controller 容器
學(xué)無止境
XCTest 測試實(shí)戰(zhàn)
iOS 7
Layer 中自定義屬性的動(dòng)畫
第一期-更輕量的 View Controllers
精通 iCloud 文檔存儲
代碼審查的藝術(shù):Dropbox 的故事
GPU 加速下的圖像視覺
Artsy
照片擴(kuò)展
理解 Scroll Views
使用 VIPER 構(gòu)建 iOS 應(yīng)用
Android 中的 SQLite 數(shù)據(jù)庫支持
Fetch 請求
導(dǎo)入大數(shù)據(jù)集
iOS 開發(fā)者的 Android 第一課
iOS 上的相機(jī)捕捉
語言標(biāo)簽
同步案例學(xué)習(xí)
依賴注入和注解,為什么 Java 比你想象的要好
編譯器
基于 OpenCV 的人臉識別
玩轉(zhuǎn)字符串
相機(jī)工作原理
Build 過程

Playground 快速原型制作

由于使用 Cocoa 框架能夠快速地創(chuàng)建一個(gè)可用的應(yīng)用,這讓許多開發(fā)者都喜歡上了 OS X 或 iOS 開發(fā)。如今即使是小團(tuán)隊(duì)也能設(shè)計(jì)和開發(fā)復(fù)雜的應(yīng)用,這很大程度上要?dú)w功于這些平臺所提供的工具和框架。Swift 的 Playground 不僅繼承了快速開發(fā)的傳統(tǒng),并且有改變我們設(shè)計(jì)和編寫 OS X 和 iOS 應(yīng)用方式的潛力。

向那些還不熟悉這個(gè)概念的讀者解釋一下,Swift 的 playground 就像是一個(gè)可交互的文檔,在其中你可以輸入 Swift 代碼讓它們立即編譯執(zhí)行。操作結(jié)果隨著執(zhí)行的時(shí)間線一步步被展示,開發(fā)者能在任何時(shí)候輸出和監(jiān)視變量。Playground 既可以在現(xiàn)有的 Xcode 工程中進(jìn)行創(chuàng)建,也能作為單獨(dú)的包存在。

Swift 的 playground 主要還是作為學(xué)習(xí)這門語言的工具而被重視,然而我們只要關(guān)注一下類似項(xiàng)目,如 IPython notebooks,就能看到交互編程環(huán)境在更廣闊的范圍內(nèi)的潛在應(yīng)用。從科學(xué)研究機(jī)器視覺實(shí)驗(yàn),這些任務(wù)現(xiàn)在都使用了 IPython notebooks。這種方式也被用來探索其他語言的范例,如 Haskell 的函數(shù)式編程。

接下來我們將探索 Swift 的 playground 在文檔、測試和快速原型方面的用途。本文使用的所有 Swift playground 源碼可以在這里下載。

將 Playground 用于文檔和測試

Swift 是一個(gè)全新的語言,許多人都使用 playground 來了解其語法和約定。不光是語言,Swift 還提供了一個(gè)新的標(biāo)準(zhǔn)庫。目前這個(gè)標(biāo)準(zhǔn)庫的文檔中對于方法的說明不太詳細(xì),所以雨后春筍般的涌現(xiàn)了許多像 practicalswift.org 標(biāo)準(zhǔn)庫方法列表這樣的資源。

編者注這里有一份自動(dòng)生成和整理的 Swift 標(biāo)準(zhǔn)庫文檔,可以作為參考。

不過通過文檔知道方法的作用是一回事,在代碼中實(shí)際調(diào)用又是另一回事。特別是許多方法在新語言 Swift 的 collection class 中能表現(xiàn)出有趣的特性,因此如果能在 collections 里實(shí)際檢驗(yàn)它們的作用將非常有幫助。

Playground 展示語法和實(shí)時(shí)執(zhí)行真實(shí)數(shù)據(jù)的特性,為編寫方法和庫接口提供了很好的機(jī)會。為了介紹 Collection 方法的使用,我們創(chuàng)建了一個(gè)叫 CollectionOperations.playground 的例子,其中包含了一系列 collection 方法的例子,所有的樣例數(shù)據(jù)都能實(shí)時(shí)修改。

例如,我們創(chuàng)建了如下的初始數(shù)組:

let testArray = [0, 1, 2, 3, 4]

然后想試試 filter() 方法:

let odds = testArray.filter{$0 % 2 == 1}

最后一行顯示這個(gè)操作所得到的結(jié)果的數(shù)組為: [1, 3]。通過實(shí)時(shí)編譯我們能了解語法、寫出例子以及獲得方法如何使用的說明,所有這些就如一個(gè)活的文檔展示在眼前。

這對于其他的蘋果框架和第三方庫都奏效。 例如,你可能想給其他人展示如何使用 Scene Kit,這是蘋果提供的一個(gè)非常棒的框架,它能在 Mac 和 iOS 上快速構(gòu)建3D場景?;蛟S你會寫一個(gè)示例應(yīng)用,不過這樣展示的時(shí)候就要構(gòu)建和編譯。

在例子 SceneKitMac.playground 中,我們已經(jīng)建立了一個(gè)功能完備帶動(dòng)畫的 3D 場景。你需要打開 Assistant Editor (在菜單上依次點(diǎn)擊 View | Assistant Editor | Show Assistant Editor),3D 效果和動(dòng)畫將會被自動(dòng)渲染。這不需要編譯循環(huán),而且任何的改動(dòng),比如改變顏色、幾何形狀、亮度等,都能實(shí)時(shí)反映出來。使用它能在一個(gè)交互例子中很好的記錄和介紹如何使用框架。

除了展示方法和方法的操作,你還會注意到通過檢查輸出的結(jié)果,我們可以驗(yàn)證一個(gè)方法的執(zhí)行是否正確,甚至在加載到 playground 的時(shí)候就能判斷方法是否被正確解析。不難想象我們也可以在 playground 里添加斷言,以及創(chuàng)建真正的單元測試?;蛘吒M(jìn)一步,創(chuàng)建出符合條件的測試,從而在你打字時(shí)就實(shí)現(xiàn)測試驅(qū)動(dòng)開發(fā)。

事實(shí)上,在 2014 年 7 月號的 PragPub 雜志中,Ron Jeffries 在他的文章 “從測試驅(qū)動(dòng)開發(fā)角度來看Swift” 中提到過這一觀點(diǎn):

Playground 很大程度上會對我們?nèi)绾螆?zhí)行測試驅(qū)動(dòng)開發(fā)產(chǎn)生影響。Playground 能夠快速展示我們所能做的東西,因此我們將比之前走得更快。但是同過去的測試驅(qū)動(dòng)開發(fā)框架結(jié)合在一起時(shí),能否走的更好?我們是否能提煉出更好的代碼,以滿足更少的缺陷數(shù)量和重構(gòu)?

關(guān)于代碼質(zhì)量的問題還是留給別人回答吧,接下來我們一起來看看 playground 如何加快一個(gè)快速原型的開發(fā)。

創(chuàng)建 Accelerate 的原型 -- 經(jīng)過優(yōu)化的信號處理

Accelerate 框架包括了許多功能強(qiáng)大的并行處理大型數(shù)據(jù)集的方法。這些方法可以利用例如 Intel 芯片中的 SSE 指令集,或者 ARM 芯片中的 NEON 技術(shù)等,這樣的現(xiàn)代 CPU 中矢量處理指令的優(yōu)勢。然而,相較于功能的強(qiáng)大,它們的接口似乎有點(diǎn)不透明,其使用的文檔也有點(diǎn)缺乏。這就導(dǎo)致許多開發(fā)者無法使用 Accelerate 這個(gè)強(qiáng)大的工具所帶來的優(yōu)勢。

Swift 提供了一個(gè)機(jī)會,通過方法重載或?yàn)?Accelerate 框架進(jìn)行包裝后,可以讓交互更加容易。這已經(jīng)在 Chris Liscio 的庫 SMUGMath 的實(shí)踐中被證實(shí),這也正是我們接下來將要?jiǎng)?chuàng)建的原型的靈感來源。

假設(shè)你有一系列正弦波的數(shù)據(jù)樣本,然后想通過這些數(shù)據(jù)來確定這個(gè)正弦波的頻率和幅度,你會怎么做呢?一個(gè)解決方案是通過傅里葉變換來算出這些值,傅里葉變換能從一個(gè)或多個(gè)重疊的正弦波提取頻率和幅度信息。Accelerate 框架提供了另一個(gè)解決方案,叫做快速傅里葉變換 (FFT),關(guān)于這個(gè)方案這里有一個(gè) (基于 IPython notebook 的) 很好的解釋。

我們在例子 AccelerateFunctions.playground 中實(shí)現(xiàn)了這個(gè)原型,你可以對照這個(gè)例子來看下面的內(nèi)容。請確認(rèn)你已經(jīng)打開 Assistant Editor (在菜單上依次點(diǎn)擊 View | Assistant Editor | Show Assistant Editor) 以查看每一階段所產(chǎn)生的圖形。

首先我們要產(chǎn)生一些用于實(shí)驗(yàn)的示例波形。使用 Swift 的 map() 方法可以很容易地實(shí)現(xiàn):

let sineArraySize = 64

let frequency1 = 4.0
let phase1 = 0.0
let amplitude1 = 2.0
let sineWave = (0..<sineArraySize).map {
    amplitude1 * sin(2.0 * M_PI / Double(sineArraySize) * Double($0) * frequency1 + phase1)
}

為了便于之后使用 FFT,我們的初始數(shù)組大小必須是 2 的冪次方。把 sineArraySize 值改為像 32,128 或 256 將改變之后顯示的圖像的密度,但它不會改變計(jì)算的基本結(jié)果。

要繪制我們的波形,我們將使用新的 XCPlayground 框架 (需要先導(dǎo)入) 和以下輔助函數(shù):

func plotArrayInPlayground<T>(arrayToPlot:Array<T>, title:String) {
    for currentValue in arrayToPlot {
        XCPCaptureValue(title, currentValue)
    }
}

當(dāng)我們執(zhí)行:

plotArrayInPlayground(sineWave, "Sine wave 1")

我們可以看到如下所示的圖表:

http://wiki.jikexueyuan.com/project/objc/images/16-1.png" alt="" />

這是一個(gè)頻率為 4.0、振幅為 2.0、相位為 0 的正弦波。為了變得更有趣一些,我們創(chuàng)建了第二個(gè)正弦波,它的頻率為 1.0、振幅為 1.0、相位為 π/2,然后把它疊加到第一個(gè)正弦波上:

let frequency2 = 1.0
let phase2 = M_PI / 2.0
let amplitude2 = 1.0
let sineWave2 = (0..<sineArraySize).map {
    amplitude2 * sin(2.0 * M_PI / Double(sineArraySize) * Double($0) * frequency2 + phase2)
}

http://wiki.jikexueyuan.com/project/objc/images/16-2.png" alt="" />

現(xiàn)在我們要將兩個(gè)波疊加。從這里開始 Accelerate 將幫助我們完成工作。將兩個(gè)個(gè)獨(dú)立地浮點(diǎn)數(shù)數(shù)組相加非常適進(jìn)行合并行處理。這里我們要使用到 Accelerate 的 vDSP 庫,它正好有這類功能的方法。為了讓這一切更有趣,我們將重載一個(gè) Swift 操作符用于向量疊加。不巧的是 + 這個(gè)操作符已經(jīng)用于數(shù)組連接 (其實(shí)挺容易混淆的),而 ++ 更適合作為遞增運(yùn)算符,因此我們將定義 +++ 作為相加的運(yùn)算符。

infix operator  +++ {}
func +++ (a: [Double], b: [Double]) -> [Double] {
    assert(a.count == b.count, "Expected arrays of the same length, instead got arrays of two different lengths")

    var result = [Double](count:a.count, repeatedValue:0.0)
    vDSP_vaddD(a, 1, b, 1, &result, 1, UInt(a.count))
    return result
}

上文定義了一個(gè)操作符,操作符能將兩個(gè) Double 類型的 Swift 數(shù)組中的元素依次合并為一個(gè)數(shù)組。在運(yùn)算中創(chuàng)建了一個(gè)和輸入的數(shù)組長度相等的空白數(shù)組(假設(shè)輸入的兩個(gè)數(shù)組長度相等)。由于 Swift 的一維數(shù)組可以直接映射成 C 語言的數(shù)組,因此我們只需要將作為參數(shù)的 Doubles 類型數(shù)組直接傳遞給 vDSP_vaddD() 方法,并在我們的數(shù)組結(jié)果前加前綴 &。

為了驗(yàn)證上述疊加是否被正確執(zhí)行,我們可以使用 for 循環(huán)以及 Accelerate 方法來繪制合并后的正弦波的結(jié)果:

var combinedSineWave = [Double](count:sineArraySize, repeatedValue:0.0)
for currentIndex in 0..<sineArraySize {
    combinedSineWave[currentIndex] = sineWave[currentIndex] + sineWave2[currentIndex]
}

let combinedSineWave2 = sineWave +++ sineWave2

plotArrayInPlayground(combinedSineWave, "Combined wave (loop addition)")
plotArrayInPlayground(combinedSineWave2, "Combined wave (Accelerate)")

http://wiki.jikexueyuan.com/project/objc/images/16-3.png" alt="" />

果然,結(jié)果是一致的。

在繼續(xù) FFT 本身之前,我們需要另一個(gè)向量運(yùn)算來處理計(jì)算的結(jié)果。Accelerate 的 FFT 實(shí)現(xiàn)中獲取的所有結(jié)果都是平方之后的,所以我們需要對它們做平方根操作。我們需要對數(shù)組中的所有元素調(diào)用類似 sqrt() 方法,這聽上去又是一個(gè)使用 Accelerate 的機(jī)會。

Accelerate 的 vecLib 庫中有很多等價(jià)的數(shù)學(xué)方法,包括平方根的 vvsqrt()。這是個(gè)使用方法重載的好例子,讓我們來創(chuàng)建一個(gè)新版本的 sqrt(),使其能處理 Double 類型的數(shù)組。

func sqrt(x: [Double]) -> [Double] {
    var results = [Double](count:x.count, repeatedValue:0.0)
    vvsqrt(&results, x, [Int32(x.count)])
    return results
}

和我們的疊加運(yùn)算符一樣,重載的平方函數(shù)輸入一個(gè) Double 數(shù)組,為輸出創(chuàng)建了一個(gè) Double 類型的數(shù)組,并將輸入數(shù)組中的所有參數(shù)直接傳遞給 Accelerate 中的 vvsqrt()。通過在 playground 中輸入以下代碼,我們可以驗(yàn)證剛剛重載的方法。

sqrt(4.0)
sqrt([4.0, 3.0, 16.0])

我們能看到,標(biāo)準(zhǔn) sqrt() 函數(shù)返回2.0,而我們的新建的重載方法返回了 [2.0, 1.73205080756888, 4.0]。這的確是一個(gè)非常易用的重載方法,你甚至可以想象照以上方法使用 vecLib 為所有的數(shù)學(xué)方法寫一個(gè)并行的版本 (不過 Mattt Thompson 已經(jīng)做了這件事)。在一臺 15 寸的 2012 年中的 i7 版本 MacBook Pro 中處理一個(gè)有一億個(gè)元素的數(shù)組,使用基于 Accelerate 的 sqrt() 方法的運(yùn)行速度比迭代使用普通的一維 sqrt() 快將近一倍。

有了這個(gè)以后,我們來實(shí)現(xiàn) FFT。我們并不打算在 FFT 設(shè)置的細(xì)節(jié)上花費(fèi)大量時(shí)間,以下是我們的 FFT 方法:

let fft_weights: FFTSetupD = vDSP_create_fftsetupD(vDSP_Length(log2(Float(sineArraySize))), FFTRadix(kFFTRadix2))

func fft(var inputArray:[Double]) -> [Double] {
    var fftMagnitudes = [Double](count:inputArray.count, repeatedValue:0.0)
    var zeroArray = [Double](count:inputArray.count, repeatedValue:0.0)
    var splitComplexInput = DSPDoubleSplitComplex(realp: &inputArray, imagp: &zeroArray)

    vDSP_fft_zipD(fft_weights, &splitComplexInput, 1, vDSP_Length(log2(CDouble(inputArray.count))), FFTDirection(FFT_FORWARD));
    vDSP_zvmagsD(&splitComplexInput, 1, &fftMagnitudes, 1, vDSP_Length(inputArray.count));

    let roots = sqrt(fftMagnitudes) // vDSP_zvmagsD returns squares of the FFT magnitudes, so take the root here
    var normalizedValues = [Double](count:inputArray.count, repeatedValue:0.0)

    vDSP_vsmulD(roots, vDSP_Stride(1), [2.0 / Double(inputArray.count)], &normalizedValues, vDSP_Stride(1), vDSP_Length(inputArray.count))
    return normalizedValues
}

第一步,我們設(shè)置了計(jì)算中需要使用到的 FFT 權(quán)重,它和我們要處理的數(shù)組大小相關(guān)。這些權(quán)重將在稍后實(shí)際的 FFT 計(jì)算中被使用到,它可以通過 vDSP_create_fftsetupD() 計(jì)算得到,并且對于給定大小的數(shù)組是可以重用的。因?yàn)樵谶@里數(shù)組的大小是個(gè)恒定的常量,因此我們只需要計(jì)算一次權(quán)重,并將它作為全局變量并在每次 FFT 中重用即可。

在 FFT 方法中,我們初始化了一個(gè)用于存放操作結(jié)果的數(shù)組 fftMagnitudes,數(shù)組的初始元素都為 0,大小為之前正弦波的大小。FFT 運(yùn)算的輸入?yún)?shù)都是實(shí)部加上虛部的復(fù)數(shù)形式,但我們真正關(guān)心的只是它的實(shí)數(shù)部分,因此我們初始化 splitComplexInput 的時(shí)候使用輸入數(shù)組作為實(shí)數(shù)部分,而將零作為虛數(shù)部分。然后 vDSP_fft_zipD()vDSP_zvmagsD() 負(fù)責(zé)執(zhí)行 FFT,并使用 fftMagnitudes 數(shù)組來存儲 FFT 從 FFT 中得到的結(jié)果的平方數(shù)。

在這里,我們使用了之前提到的基于 Accelerate 的 sqrt() 方法來計(jì)算平方根,返回實(shí)際大小,然后基于輸入數(shù)組的大小對值進(jìn)行歸一化。

對一個(gè)單一的正弦波,以上所有操作的的結(jié)果如下:

http://wiki.jikexueyuan.com/project/objc/images/16-4.png" alt="" />

疊加的正弦波看起來像這樣:

http://wiki.jikexueyuan.com/project/objc/images/16-5.png" alt="" />

對這些值一個(gè)非常簡單的解釋是:這些結(jié)果表示了正弦波頻率的集合,從左邊開始,集合中的值表示了在該頻率下檢測到的波的振幅。它們關(guān)于中心對稱,因此你可以忽略圖中右半部分的值。

可以觀察到對于頻率為 4.0 振幅為 2.0 的波,在 FFT 中是一個(gè) 位于 4 對應(yīng)于 2.0 的值。同樣對于頻率為 1.0 振幅為 1.0 的波,在 FFT 中是位于 1 對應(yīng)值為 1.0 的點(diǎn)。盡管疊加后的正弦波得到的 FFT 波形比較復(fù)雜,但是依然能夠清晰地區(qū)分合并的兩個(gè)波在各自集合內(nèi)的振幅和頻率,就仿佛它們的 FFT 結(jié)果是分別被加入的一樣。

再次強(qiáng)調(diào),這是 FFT 運(yùn)算的簡化版本,在上文的 FFT 代碼中有簡化操作,但關(guān)鍵是在 playground 中通過一步步創(chuàng)建方法,我們能輕松地探索一個(gè)復(fù)雜的信號處理操作,并且每一步操作的測試都能立即得到圖形反饋。

使用 Swift Playgrounds 快速創(chuàng)建原型的案例

我們希望這些例子能夠說明 Swift playground 在實(shí)踐新類庫和新概念上的作用。

上一個(gè)例子中的每一步里,我們都能在執(zhí)行時(shí)通過時(shí)間線中的圖案來觀察中間數(shù)組的狀態(tài)。這對于一個(gè)示例程序來說作用非常大,而且也以某種方式為程序提供了界面。所有這些圖像都實(shí)時(shí)更新,因此你能隨時(shí)返回到實(shí)現(xiàn)中并修改其中一個(gè)波的頻率或振幅,然后看著波形隨著處理步驟變化。這縮短了開發(fā)周期,并且對計(jì)算過程的體驗(yàn)提供了巨大幫助。

這種立即反饋的交互式開發(fā)是為復(fù)雜的算法創(chuàng)建原型的很好的案例。在將這樣的復(fù)雜算法部署到實(shí)際的應(yīng)用之前,我們有機(jī)會在 playground 中對它進(jìn)行驗(yàn)證和研究。

上一篇:音頻 API 一覽下一篇:測試