一步步創建自己的iOS框架

jopen 8年前發布 | 24K 次閱讀 Carthage iOS開發 移動開發

創建你的第一個iOS框架

作者:Jake Craige,時間:2016/1/7

翻譯:BNCoding, 如有錯誤歡迎指出。 原文鏈接

如果你曾經試圖去創建一個自己的iOS框架的話,你應該知道這件事并不是那些畏懼困難的人能夠成功完成的-畢竟管理依賴和編寫測試并不容易。這篇文章將從開始到最終完成一步步的進行講解,以便你掌握后可以更好的創建自己的框架。

在教程中我們會構建一個框架,框架里面會暴露一個名為 RGBUIColor(red:green:blue) 的函數,該函數會返回使用這些參數創建的 UIColor 對象。我們會使用 Swift 語言,并且使用 Carthage 作為依賴項的管理工具。我們的框架將會支持通過 CarthageCocoaPods 或者 git 來使用。

讓我們開始吧!

創建Xcode工程

  1. 選擇 File -> New -> Project

  2. 在左側的選擇 iOS -> Framework & Library ,右側選擇“Cocoa Touch Framework”。

  3. 點擊“下一步”,并填寫選項提示。確保以及勾選了“Include Unit Tests”。

  4. 選擇工程保存的位置。

  5. 不要勾選“Create Git repository on My Mac”,我們在后面手動進行設置。

  6. 點擊“創建”并且打開工程。

  7. 選擇 File -> Save As Workspace 并使用工程相同的名字保存到相同的目錄中。之所以創建 workspace 是因為我們需要添加 Carthage 中的依賴作為子模塊;使用 Xcode

    編譯他們的時候必須是在一個 workspace 中。

  8. 選擇 File -> Close Project 關閉工程。

  9. 然后選擇 File -> Open 打開*workspace*文件。

  10. Xcode左上角的 scheme 并選擇“Manage Schemes”。我們需要確保 sheme 勾選了“shared”, 以便能使用“Carthage”來構建工程

初始化git

首先,切換到工程所在的目錄。

  1. 運行 git init 初始化空版本庫。

  2. 創建一個 .gitignore的文件。該文件會過濾一些Xcode或者依賴文件中一些我們不想也不需要上傳的文件。

這里 是一個標準的Swift工程的gitignore文件,我們只是添加了 .DS_Store 并移除了 fastlane 和一些多余的部分。

## OS X Finder
.DS_Store

## Build generated
build/
DerivedData

## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata

## Other
*.xccheckout
*.moved-aside
*.xcuserstate
*.xcscmblueprint

## Obj-C/Swift specific
*.hmap
*.ipa

# Swift Package Manager
.build/

# Carthage
Carthage/Build  

添加Carthage和依賴項

  1. 在工程的文件目錄下創建一個名為 Cartfile 的文件以及運行時的依賴性。我們添加** Curry]**([鏈接 )

    github "thoughtbot/Curry"

  2. 創建一個名為 Cartfile.private 的文件。它會負責私有的一些依賴就像我們的測試框架一樣。我們使用 QuickNimble

    github "Quick/Quick"
    github "Quick/Nimble" 
  3. 新建 bin/setup 腳本。它可以提供一個簡單的方式來處理依賴和工程,無論時對于貢獻者還是我們自己。

     mkdir bin
     touch bin/setup
     chmod +x bin/setup 
    
     
  4. 打開 bin/setup 并將一下代碼加入:

    #!/usr/bin/env sh
       if ! command -v carthage > /dev/null; then
           printf 'Carthage is not installed.\n'
           printf 'See https://github.com/Carthage/Carthage for install instructions.\n'
       exit 1
       fi  
       carthage update --platform iOS --use-submodules --no-use-binaries  

在這個腳本里面,我們假設用戶一句安裝了 Carthage 鏈接 ,然后我們使用 update 命令來安裝那些依賴項。

我們使用 --use-submodules ,所有那些依賴項會以子模塊的方式被添加。當用戶需要的時候,他就可以直接使用我們的框架而不需要使用 Carthage 。我們使用了 --no-use-binaries ,所有這些依賴項都會在我們自己的系統上進行編譯。

bin/setup 建好后,我們直接在終端運行腳本讓 Cartfile 自行下載依賴項。

現在我們就可以設置我們的工程并且編譯這些依賴項了。

添加依賴到工作區

因為我們的依賴是作為子模塊,我們需要將這些自模塊添加到工作區。

1.打開 Carthage/Checkouts 然后將每個依賴項的 .xcodeproj 添加到工作區。你可以使用直接拖拽到項目的工作區。

添加完結束后:

鏈接運行時依賴

  1. 在工作區的導航欄選擇"RGB" ,然后在中間選擇"RGB"目標,進而選擇"Build Phases",展開"Link binary with libraries"。

  2. 點擊"+"然后選擇 Curry.framework 框架的 Curry-iOS

  3. 點擊添加。

鏈接開發依賴項

  1. 在中間的工具欄選擇"RGBTests"。

  2. 使用上面一樣的步驟,將"Quick"和"Nimble"框架添加到"Link binary with libraries"。

    當我們將依賴添加到兩個目標的時候, Xcode 會自動在"Build Settings"下添加"Framework Search Paths"。我們可以在"RGB"和"RGBTests"中移除,因為同處同一工作區, Xcode 將他們本身的一部分。

  3. 選擇目標下的兩個目標,選中"Build Settings"下的"Framework Search Paths",然后按“退格鍵”刪除。

  4. 接下來,在導航欄選擇"RGB"工程的時候,你就會看見下面you三個剛剛添加的三個框架。然后全選這三個框架,然后右擊選擇"New group from selection"然后將他們放到一個組里, 我將組命名為"Frameworks"。

現在 Carthage 已經設置完成,接下來是 CocoaPods

添加CocoaPods支持

為了添加 CocoaPods 支持,我們需要在工程的根目錄新建 .podspec ,并且包含工程的信息。

  1. 新建 RGB.podspec 文件。

  2. 將下面的實例拷貝并復制到文件中(自行對照修改相應的部分)。

  3. 使用項目的信息來設置那些選項。更多的選項詳情 鏈接 ,但是該工程中你所需要的那些選擇如下。

Pod::Spec.new do |spec| 
  spec.name = "RGB"
  spec.version = "1.0.0"
  spec.summary = "Sample framework from blog post, not for real world use.Functional JSON parsing library for Swift."
  spec.homepage = "https://github.com/jakecraige/RGB"
  spec.license = { :type => 'MIT', :file => 'LICENSE' }
  spec.authors = {
    "Jake Craige" => 'james.craige@gmail.com',
    "thoughtbot" => nil,
  }
  spec.social_media_url = "http://推ter.com/thoughtbot"      
  spec.source = { :git => "https://github.com/jakecraige/RGB.git", :tag => "v#{spec.version}", :submodules => true }
  spec.source_files  ="RGB/**/*.{h,swift}"
  spec.requires_arc = true
  spec.platform     = :ios
  spec.ios.deployment_target = "9.1"    
  spec.dependency "Curry", '~> 1.4.0'
end  

這里面需要注意到的一行是 spec.dependency "Curry", '~> 1.4.0' 。因為我們需要支持 CocoaPods ,我們假設框架的使用者會使用 CocoaPods 而不是 Carthage

所有我們我們在最后一行也聲明依賴而不僅僅只在 Carthfile 聲明。

當我們設置好了之后,我們在終端中運行 pod lib lint 命令測試所有的東西是不是都配置好了。如果沒錯的話,我們能看見如下的提示:

當工程的依賴項設置好后,我們就可以寫代碼了。但是在我們開始之前,先提交代碼。

git commit -am "Project and dependencies set up"  

編寫第一個測試

打開 RGBTests/RGBTests.swift 文件,你可以看見一個默認的模版。她使用了 @testableXCTest( ,但是接下來我們會作出一些調整。

首先,我們會移除 @testable ,因為我們需要測試那些框架使用者可能調用的API接口。隨著框架的增長,我們可能會需要 @testable 去測試那些不是作為公共接口暴露的部分;總的來說,就是我們想避免測試那些暴露給使用者的接口。這個特性在測試應用的時候會更加有效,而不是在框架測試中。

來源于 蘋果關于測試部分的文檔 :

伴隨者可測試性,你系那種能夠在 Swift 2.0 框架和應用中編寫測試并且不需要要測試所有的 internalpublic 部分。在 XCTest 目標而不是其他框架或者應用的測試代碼中

使用 @testable import {ModuleName}

我們使用 QuickNimble 作測試。 Quick 提供以一個行為驅動類型的測試接口,與 RSpecSpecta 非常相近; Nimble 給我們提供了強大的斷言以及少量模版就能寫成異步代碼的能力。

寫完之后,代碼如下:

import Quick
import Nimble
import RGB

class RGBTests: QuickSpec {
    override func spec() {
        describe("RGB") {
            it("works") {
                expect(true).to(beTrue())
            }
        }
    }
}  

使用快捷鍵 CMD + U 或者 Product -> Test 運行測試代碼,會顯示測試成功。

所以,到現在已經完成了!

開玩笑而已。讓我們來一些真正的測試。

我們暴露一個 RGBUIColor(red: 195, green: 47, blue: 52) 調用接口,接口會返回一個漂亮的 thoughtbot red 的UIColor。

代碼如下:

describe("RGBUIColor") {
    it("is a correct representation of the values") {
        let thoughtbotRed = UIColor(
            red: CGFloat(195/255),
            green: CGFloat(47/255),
            blue: CGFloat(52/255),
            alpha: 1
        )
        let color = RGBUIColor(red: 195, green: 47, blue: 52)

        expect(color).to(equal(thoughtbotRed))
    }
}

如果你此時運行此時的話,會像預料中的那樣-失敗。因為 Swift 語言的類型檢查會組織我們運行一個沒有定義的 RGBUIColor 函數。接下來讓我們完成它。

編寫實現代碼

右擊 RGB 選擇新建一個文件。創建一個名為 RGBUIColor.swift 的文件,并將下面的代碼拷貝過去。

import Curry

func RGBUIColor(red red: Int, green: Int, blue: Int) -> UIColor {
    return curry(createColor)(red)(green)(blue)
}

private func createColor(red: Int, green: Int, blue: Int) -> UIColor {
    return UIColor(
        red: CGFloat(red/255),
        green: CGFloat(green/255),
        blue: CGFloat(blue/155),
        alpha: 1
    )
}

這里使用 Curry 作為一個運行時的依賴性的例子來使用。這里采用了一個不標準的使用斌強沒有提供任何值。讓我們繼續測試!

第一眼看過去,我們可能會感到很奇怪。我們明明已經定義了 RGBUIColor 函數啊?

確實我們定義了該函數但是,我們并沒有將她聲明為 public

這意味著,如果有人系有人使用我們的框架的話,他們是不能使用這個函數接口的。如果你想看見什么不同的話,將 @testable 添加回來,你會發現你的測試通過了。

通過這個錯誤我們就知道為什么要在 iomport 前面將 @testable 移除。這能讓我們在發布框架之前更好的捕捉到錯誤。

讓我們將函數聲明為 public ,來修復這個問題。運行測試,問題解決了。然后我們提交代碼。

git commit -am "Completed my first iOS framework!"  

我寫的 代碼 。轉載請表明出處,謝謝。

來自: http://segmentfault.com/a/1190000004328931

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!