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

照片擴(kuò)展

在 iOS 8 發(fā)布時(shí),蘋(píng)果把六種全新擴(kuò)展功能介紹給全世界,它們史無(wú)前例的提供了訪問(wèn)操作系統(tǒng)的可行性?,F(xiàn)在,開(kāi)發(fā)者可以利用照片擴(kuò)展來(lái)為系統(tǒng)相機(jī)應(yīng)用增加功能。

用戶使用照片編輯擴(kuò)展的流程并不簡(jiǎn)單。從選擇編輯的照片開(kāi)始,需要點(diǎn)擊三次才能啟動(dòng),其中一步驟是非常小一個(gè)按鈕:

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

然而,這類(lèi)擴(kuò)展給開(kāi)發(fā)者提供了為用戶創(chuàng)造無(wú)縫體驗(yàn),創(chuàng)建一致的方法來(lái)管理照片的絕佳的機(jī)會(huì)。

本文在了解更詳細(xì)的編輯工作流程之前,將先簡(jiǎn)單討論如何創(chuàng)建擴(kuò)展以擴(kuò)展的生命周期,我們會(huì)通過(guò)常見(jiàn)的相關(guān)問(wèn)題和場(chǎng)景來(lái)創(chuàng)建照片編輯擴(kuò)展從而得出結(jié)論。

本文的示例項(xiàng)目 Filtster 演示了如何創(chuàng)建自己的圖片編輯擴(kuò)展。它詮釋使用了數(shù)個(gè) Core Image 濾鏡完成簡(jiǎn)單的圖像過(guò)濾效果。完整 Filtster 項(xiàng)目代碼 可以在 GitHub 上找到。

創(chuàng)建擴(kuò)展

所有擴(kuò)展必須包含在一個(gè)功能齊全的 iOS 應(yīng)用程序之內(nèi),照片編輯擴(kuò)展也不例外。這可能意味著你必須做很多令人吃驚的自定義 Core Image 濾鏡的才能讓它到達(dá)用戶手中。蘋(píng)果如何嚴(yán)格審查還有待觀察,因?yàn)樘O(píng)果商店內(nèi)的大多數(shù)有圖片編輯功能的應(yīng)用都是在 iOS 8 引入之前就已經(jīng)存在了的。

為了創(chuàng)建新的圖片編輯擴(kuò)展,需要為已有的 iOS 項(xiàng)目添加新的 target,擴(kuò)展 target 模板如下:

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

模板由三部分組成:

  1. Storyboard 圖片編輯擴(kuò)展除了系統(tǒng)在頂部提供的 toolbar 包含取消以及完成按鈕之外,界面幾乎完全可以自定義。

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

雖然 storyboard 默認(rèn)不包含 size classes,系統(tǒng)將允許你選擇并激活該功能,雖然沒(méi)有明顯的原因來(lái)阻止你使用手動(dòng)布局,但蘋(píng)果還是強(qiáng)烈建議使用 Auto Layout 來(lái)創(chuàng)建照片編輯擴(kuò)展。如果你忽略蘋(píng)果的建議你將不得不面對(duì)很多潛在風(fēng)險(xiǎn)。
  1. Info.plist 設(shè)定擴(kuò)展的類(lèi)型和可被接受媒體的類(lèi)型,以及擴(kuò)展的通用配置。NSExtension 鍵值是一個(gè)字典,它包含擴(kuò)展所需要的配置:

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

`NSExtensionPointIdentifier` 實(shí)體告訴系統(tǒng)這是一個(gè)使用 `com.apple.photo-editing` 作為值的照片編輯擴(kuò)展。唯一特殊的 key 是 `PHSupportedMediaTypes`,它指明可以被操作的媒體類(lèi)型。在默認(rèn)情況下,這是一個(gè)包含 `Image` 實(shí)體的數(shù)組,當(dāng)然你也可添加 `Video` 選項(xiàng)。
  1. View Controller 遵守 PHContentEditingController 協(xié)議,其中包含了圖片編輯擴(kuò)展需要的生命周期方法。更多詳情見(jiàn)本文下個(gè)部分。

值得注意的是不要忘記提供菜單內(nèi)的擴(kuò)展的圖標(biāo):

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

圖標(biāo)通過(guò)宿主 app 的資源目錄內(nèi)的 App Icon 提供。這里文檔有些讓人迷惑,它暗示你必須在擴(kuò)展本身里來(lái)提供圖標(biāo)。然而,盡管我們可以提供一個(gè)這樣的圖標(biāo),但擴(kuò)展將不會(huì)使用選擇它。這一點(diǎn)有些爭(zhēng)議,因?yàn)樘O(píng)果指定與擴(kuò)展相關(guān)的圖標(biāo)必須與容器應(yīng)用程序的相同。

擴(kuò)展的生命周期

照片編輯擴(kuò)展建立于 Photos 框架之上的,這意味著編輯不是破壞性的。當(dāng)一個(gè)照片資源被編輯的時(shí)候,原始文件始終沒(méi)有被修改,編輯的結(jié)果將作為副本被保存下來(lái)。另外,語(yǔ)義細(xì)節(jié)包含了如何重新編輯并保存調(diào)整后的數(shù)據(jù)。這個(gè)數(shù)據(jù)的意思是編輯可以基于原始文件重新來(lái)過(guò)。當(dāng)你實(shí)現(xiàn)圖片編輯擴(kuò)展的時(shí)候,你只負(fù)責(zé)構(gòu)建你自己的數(shù)據(jù)對(duì)象。

PHAdjustmentData 類(lèi)含有編輯所需參數(shù),以及兩個(gè)格式化的屬性 (formatIdentifierformatVersion) 用來(lái)確定當(dāng)前編輯擴(kuò)展針對(duì)于之前的編輯過(guò)的照片的兼容性。它們兩個(gè)都是字符串類(lèi)型,另外 formatIdentifier 規(guī)定為反向域名解析格式。這兩個(gè)屬性讓你靈活的創(chuàng)建一套圖像編輯的應(yīng)用程序以及擴(kuò)展,每一種都可以用另一種表示。另外 data 屬性是 NSData 類(lèi)型??梢员挥脕?lái)按你的需要存儲(chǔ)擴(kuò)展操作的細(xì)節(jié),以便讓你的擴(kuò)展能繼續(xù)編輯。

開(kāi)始編輯

當(dāng)用戶使用你的擴(kuò)展來(lái)編輯照片的時(shí)候,系統(tǒng)會(huì)實(shí)例化你的視圖控制器并且初始化照片編輯的生命周期。如果照片之前曾經(jīng)被編輯,它首先會(huì)調(diào)用 canHandleAdjustmentData(_:) 方法,同時(shí)為你提供一個(gè) PHAdjustmentData 對(duì)象。因此,你的擴(kuò)展是否可以處理之前編輯過(guò)的數(shù)據(jù)就很重要,這將決定框架發(fā)送的下一個(gè)生命周期的方法是什么。

一旦系統(tǒng)決定提供原始圖片還是之前就被渲染編輯過(guò)的圖片,接下來(lái)將會(huì)調(diào)用 startContentEditingWithInput(_:, placeholderImage:)。輸入是一個(gè)類(lèi)型為 PHContentEditingInput 的對(duì)象,其中包含了地理位置,創(chuàng)建時(shí)間以及媒體類(lèi)型等來(lái)自于原始資源的元數(shù)據(jù),以及你需要編輯的資源細(xì)節(jié)。除了原始尺寸的輸入圖片的路徑以外,輸入對(duì)象還包含一個(gè) displaySizedImage 表示相同的圖片數(shù)據(jù),但是根據(jù)屏幕尺寸進(jìn)行了適當(dāng)縮放。這意味著交互編輯可以在較低分辨率下進(jìn)行,以此來(lái)確保擴(kuò)展可以保持迅速響應(yīng)操作并節(jié)省能量。

下面是實(shí)現(xiàn)方法

func startContentEditingWithInput(contentEditingInput: PHContentEditingInput?,
                                  placeholderImage: UIImage) {
  input = contentEditingInput
  filter.inputImage = CIImage(image: input?.displaySizeImage)
  if let adjustmentData = contentEditingInput?.adjustmentData {
    filter.importFilterParameters(adjustmentData.data)
  }

  vignetteIntensitySlider.value = Float(filter.vignetteIntensity)
  ...
}

上面的實(shí)現(xiàn)中存儲(chǔ)了 contentEditingInput,因?yàn)橐瓿删庉嫴恼{(diào)整后的數(shù)據(jù)導(dǎo)入濾鏡參數(shù)的時(shí)候我們會(huì)需要它。

如果你的 canHandleAdjustmentData(_:) 返回 true,startContentEditingWithInput(_:, placeholderImage:) 將會(huì)提供原始圖片,然后你的擴(kuò)展需要根據(jù)調(diào)整后的數(shù)據(jù)來(lái)重新創(chuàng)建編輯過(guò)的圖片。如果這是一個(gè)耗時(shí)操作,那么 placeholderImage 將提供一個(gè)上次編輯渲染后的臨時(shí)圖片來(lái)讓你暫時(shí)使用。

在這個(gè)階段,用戶將通過(guò)擴(kuò)展界面的交互來(lái)控制編輯的進(jìn)程。因?yàn)閿U(kuò)展包含一個(gè)視圖控制器,你可以使用任何 UIKit 來(lái)實(shí)現(xiàn)它。示例項(xiàng)目使用了 Core Image 的濾鏡鏈來(lái)完成編輯,所以界面使用了一個(gè)自定義的 GLKView 子類(lèi)來(lái)減少 CPU 的負(fù)載。

取消編輯

在完成編輯時(shí),用戶可以選擇照片界面提供的取消或者完成按鈕。如果想讓用戶確定是否取消尚未保存的編輯內(nèi)容,shouldShowCancelConfirmation 屬性需要重寫(xiě)并返回 true

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

如果需要取消操作,cancelContentEditing 方法將被調(diào)用來(lái)允許你清空所有臨時(shí)數(shù)據(jù)。

提交修改

一旦用戶決定保存編輯操作,并且點(diǎn)擊了完成按鈕,finishContentEditingWithCompletionHandler(_:) 將會(huì)被調(diào)用。在這個(gè)時(shí)候,原始尺寸圖像需要用與當(dāng)前顯示的圖片相同設(shè)置來(lái)編輯,并保存調(diào)整后的數(shù)據(jù)。

在這時(shí),你可以通過(guò)在編輯過(guò)程開(kāi)始時(shí)提供的 PHContentEditingInput 對(duì)象內(nèi)的 fullSizeImageURL 來(lái)獲取原始尺寸的圖片。

要完成編輯,我們需要調(diào)用提供的回調(diào)函數(shù),并提供一個(gè)從輸入創(chuàng)建的 PHContentEditingOutput 對(duì)象。這個(gè)輸出對(duì)象還包含了一個(gè) renderedContentURL 屬性,用來(lái)指定你應(yīng)該把輸出的 JPEG 數(shù)據(jù)存放在哪里:

func finishContentEditingWithCompletionHandler(completionHandler: ((PHContentEditingOutput!) -> Void)!) {
  // 在后臺(tái)隊(duì)列渲染并提供輸出。
  dispatch_async(dispatch_get_global_queue(CLong(DISPATCH_QUEUE_PRIORITY_DEFAULT), 0)) {

    // 從編輯輸入創(chuàng)建編輯輸出。

    let output = PHContentEditingOutput(contentEditingInput: self.input)

    // 提供調(diào)整后的數(shù)據(jù)并且渲染輸出到指定位置。   

    let adjustmentData = PHAdjustmentData(formatIdentifier: self.filter.filterIdentifier,
      formatVersion: self.filter.filterVersion, data: self.filter.encodeFilterParameters())
    output.adjustmentData = adjustmentData

    // 寫(xiě)入 JPEG 圖片

    let fullSizeImage = CIImage(contentsOfURL: self.input?.fullSizeImageURL)
    UIGraphicsBeginImageContext(fullSizeImage.extent().size);
    self.filter.inputImage = fullSizeImage
    UIImage(CIImage: self.filter.outputImage)?.drawInRect(fullSizeImage.extent())

    let outputImage = UIGraphicsGetImageFromCurrentImageContext()
    let jpegData = UIImageJPEGRepresentation(outputImage, 1.0)
    UIGraphicsEndImageContext()

    jpegData.writeToURL(output.renderedContentURL, atomically: true)

    // 調(diào)用完成回調(diào)提交編輯后的圖片。

    completionHandler?(output)
  }
}

一旦對(duì) completionHandler 返回,你就可以清空臨時(shí)數(shù)據(jù),并且修改后的文件已經(jīng)準(zhǔn)備好從擴(kuò)展返回。

常見(jiàn)問(wèn)題

與創(chuàng)建圖片編輯擴(kuò)展相關(guān)的內(nèi)容其中一些可能有些復(fù)雜,本節(jié)內(nèi)容將介紹最重要的幾個(gè)。

調(diào)整數(shù)據(jù) (Adjustment Data)

PHAdjustmentData 是一個(gè)只包含三個(gè)屬性的簡(jiǎn)單類(lèi),但是想要用好的話,依然需要遵循一些規(guī)則。蘋(píng)果建議使用反向域名解析格式來(lái)指定 formatIdentifier,但是 formatVersiondata 如何使用將由你自己決定。

重要的是要確保你不同版本圖片編輯擴(kuò)展的兼容性,所以我們需要類(lèi)似語(yǔ)義化版本這樣能提供靈活的管理產(chǎn)品的生命周期的方式。你可以以自己的方式進(jìn)行解析,也可以依賴于像 SemverKit 之類(lèi)的第三方框架提供的功能。

最后對(duì)于調(diào)整數(shù)據(jù)要說(shuō)的是 data 本身,它是一個(gè) NSData 數(shù)據(jù)對(duì)象。蘋(píng)果提供的唯一建議是它應(yīng)該用來(lái)存放重建編輯時(shí)所需要的的設(shè)定,而不是編輯本身,這是因?yàn)?PHAdjustmentData 對(duì)象的尺寸是受 Photo 框架限制的。

對(duì)于不是很復(fù)雜的擴(kuò)展 (比如 Filtster),這個(gè)數(shù)據(jù)可以是簡(jiǎn)單地對(duì)一個(gè)字典歸檔,代碼如下:

public func encodeFilterParameters() -> NSData {
  var dataDict = [String : AnyObject]()
  dataDict["vignetteIntensity"] = vignetteIntensity
  ...
  return NSKeyedArchiver.archivedDataWithRootObject(dataDict)
}

接著提供解析方式:

public func importFilterParameters(data: NSData?) {
  if let data = data {
    if let dataDict = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? [String : AnyObject] {
      vignetteIntensity = dataDict["vignetteIntensity"] as? Double ?? vignetteIntensity
      ...
    }
  }
}

這里,這兩個(gè)方法存在于共享的 FiltsterFilter 類(lèi)中,同時(shí)這個(gè)類(lèi)也負(fù)責(zé)確定調(diào)整數(shù)據(jù)的兼容性:

public func supportsFilterIdentifier(identifier: String, version: String) -> Bool 
  return identifier == filterIdentifier && version == filterVersion
}

如果你有更復(fù)雜的需求,你可以創(chuàng)建一個(gè)自定義的設(shè)置類(lèi),讓它支持 NSCoding 協(xié)議并用類(lèi)似的方式進(jìn)行歸檔。

用戶需要可以將互不兼容的照片編輯串聯(lián)起來(lái) -- 如果當(dāng)前擴(kuò)展無(wú)法理解調(diào)整數(shù)據(jù)的話,一張預(yù)先渲染好的圖像將被作為輸入。比如你可以使用系統(tǒng)的裁剪工具先對(duì)圖片進(jìn)行裁剪,然后再在你的自定義照片編輯擴(kuò)展中使用。在你存儲(chǔ)編輯后的圖像時(shí),與之綁定的編輯數(shù)據(jù)只會(huì)包含最近的編輯的細(xì)節(jié)。你可以將之前的不兼容的編輯的調(diào)整數(shù)據(jù)保存到你的輸出調(diào)整數(shù)據(jù)中,這樣你就可以為濾鏡鏈中你的階段實(shí)現(xiàn)還原功能。Photo 框架提供的還原功能將移除所有編輯,并把照片恢復(fù)到原始狀態(tài):

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

代碼/數(shù)據(jù)共享

照片編輯擴(kuò)展作為一個(gè)嵌入式二進(jìn)制文件包含在容器應(yīng)用中。因?yàn)樘O(píng)果要求這個(gè)容器應(yīng)用必須有完整功能,因此你創(chuàng)建的照片編輯擴(kuò)展,很可能與容器應(yīng)用有相同的功能。你可能會(huì)希望在應(yīng)用擴(kuò)展和容器之間共享代碼和數(shù)據(jù)。

共享代碼通過(guò) iOS 8 新功能 -- 創(chuàng)建 Cocoa Touch 框架 target 來(lái)實(shí)現(xiàn)。你可以向其中添加共用的功能,例如濾鏡鏈和自定義視圖類(lèi),并在應(yīng)用和擴(kuò)展中同時(shí)使用。

值得注意的是因?yàn)橛糜趧?chuàng)建擴(kuò)展,你必須在 Target 設(shè)置界面將 API 兼容性限制為僅擴(kuò)展可用:

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

共享數(shù)據(jù)的需求明顯要少很多,在許多情況下并不存在。然而如果需要,你可以通過(guò)把應(yīng)用和擴(kuò)展都添加到一個(gè)關(guān)聯(lián)到你的開(kāi)發(fā)者賬號(hào)的 app group 中的方式,來(lái)創(chuàng)建一個(gè)共享容器 (shared container)。共享容器代表的是磁盤(pán)上的一塊共享的空間,你可以使用任何你喜歡的方式使用它,比如 NSUserDefaults,SQLite 或者寫(xiě)文件。

調(diào)試與分析

Xcode 調(diào)試雖然有一些潛在癥結(jié),但已經(jīng)相當(dāng)友好了。選擇擴(kuò)展的 scheme 并編譯運(yùn)行,接著會(huì)詢問(wèn)你希望啟動(dòng)哪一個(gè)應(yīng)用,因?yàn)閳D片編輯擴(kuò)展只能在系統(tǒng)照片應(yīng)用中實(shí)現(xiàn),所以你應(yīng)該選擇照片應(yīng)用:

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

如果這么做啟動(dòng)的是你的容器應(yīng)用的話,你可以編輯擴(kuò)展 scheme 設(shè)置 executable 為 Ask on Launch 來(lái)解決。

Xcode 然后會(huì)等待你打開(kāi)你的照片編輯擴(kuò)展,然后將調(diào)試器掛載上去。從這時(shí)開(kāi)始,你就可以用調(diào)試標(biāo)準(zhǔn) iOS 應(yīng)用的方式來(lái)調(diào)試擴(kuò)展了。將調(diào)試器附加到擴(kuò)展可能需要一些時(shí)間,所以當(dāng)你激活擴(kuò)展時(shí),擴(kuò)展可能會(huì)失去響應(yīng)一段時(shí)間。如果你想評(píng)估啟動(dòng)時(shí)間的話,可以在 release 模式下運(yùn)行它。

性能分析和調(diào)試類(lèi)似,分析器在擴(kuò)展開(kāi)始執(zhí)行后附加上去。你可以更新擴(kuò)展相關(guān) scheme 指定 Xcode 詢問(wèn)應(yīng)該啟動(dòng)哪一個(gè)應(yīng)用來(lái)執(zhí)行分析。

內(nèi)存限制

擴(kuò)展不是一個(gè)全功能 iOS 應(yīng)用,因此訪問(wèn)系統(tǒng)資源時(shí)要受到限制。更特別的是,如果用戶使用太多內(nèi)存,系統(tǒng)將優(yōu)先關(guān)閉擴(kuò)展進(jìn)程。我們無(wú)法確定具體的內(nèi)存限制,因?yàn)閮?nèi)存管理是由 iOS 內(nèi)部處理的,但有這肯定是基于像是設(shè)備,宿主應(yīng)用,以及其他應(yīng)用程序的內(nèi)存壓力這些因素的。所以其實(shí)并沒(méi)有硬性的限制,但我們還是應(yīng)該盡量減少內(nèi)存占用。

圖片處理是一個(gè)高內(nèi)存操作,特別是處理的對(duì)象是來(lái)自 iPhone 相機(jī)的高清晰度圖片。你需要做幾件事情來(lái)確保照片編輯擴(kuò)展的內(nèi)存使用量降到最低。

  • 使用顯示尺寸的圖片 當(dāng)你開(kāi)始編輯進(jìn)程時(shí),系統(tǒng)提供了一張適合屏幕尺寸的圖片。用它來(lái)替代原始圖片,將在交互編輯階段將顯著減少內(nèi)存使用。
  • 限制 Core Graphics 上下文數(shù)量 雖然使用 Core Graphics 來(lái)處理圖片是正確的方式,但不要忘記 Core Graphics 上下文其實(shí)是一大塊內(nèi)存。如果你需要上下文,那么需要保持?jǐn)?shù)量到最低。盡可能的重用,并想想你是否以最佳的方式在使用它。
  • 使用 GPU 無(wú)論通過(guò) Core Image 還是類(lèi)似 GPUImage 的第三方框架來(lái)用 GPU 進(jìn)行處理,你可以通過(guò)鏈?zhǔn)秸{(diào)用濾鏡來(lái)降低內(nèi)存并且消除中間緩存區(qū)需求。

因?yàn)閳D像編輯本身肯定就需要高內(nèi)存,所以與其他擴(kuò)展相比,照片編輯擴(kuò)展的可用內(nèi)存要多那么一些。在 ad hoc 測(cè)試中,圖片編輯擴(kuò)展可以使用高于 100 MB 內(nèi)存。鑒于來(lái)自 800 萬(wàn)像素相機(jī)的照片大約 22MB,所以這個(gè)內(nèi)存量對(duì)于大多數(shù)圖片編輯擴(kuò)展來(lái)說(shuō)是夠用的。

結(jié)論

iOS 8 之前,第三方開(kāi)發(fā)者無(wú)法在他自己應(yīng)用程序之外向用戶提供功能。擴(kuò)展的出現(xiàn)徹底改變這一狀況,特別是照片編輯擴(kuò)展允許你把代碼運(yùn)行于照片應(yīng)用核心中。盡管多次點(diǎn)擊的流程略顯復(fù)雜,但照片編輯擴(kuò)展使用 Photo 框架的功能提供了連貫和集成的用戶體驗(yàn)。

可恢復(fù)的編輯一直是像 Aperture 或 Lightroom 這樣的桌面應(yīng)用的殺手級(jí)功能。而現(xiàn)在在 iOS 中使用 Photo 框架,也可以為這個(gè)功能創(chuàng)建一個(gè)通用架構(gòu)。這具有巨大的潛力,而允許第三方開(kāi)發(fā)者創(chuàng)建照片編輯擴(kuò)展則使這一步走得更遠(yuǎn)。

制作照片編輯擴(kuò)展方面有不少?gòu)?fù)雜的課題,但是它們都不是獨(dú)一無(wú)二的。創(chuàng)建一個(gè)直觀的用戶界面,以及設(shè)計(jì)圖像處理算法都和圖片編輯擴(kuò)展一樣充滿了挑戰(zhàn)性,而它們都是一個(gè)完整的圖片編輯應(yīng)用的組成部分。

目前為止有多少用戶留意到這些第三方編輯擴(kuò)展還有待觀察,但總的來(lái)說(shuō)這有助于提高你應(yīng)用曝光率。