当前位置 > 主页 > 万和大讲堂 >


南京iOS应用开发培训——一步步创建自己的 iOS 框架

2016-03-11 17:56

  在教程中我们会构建一个框架,框架里面会暴露一个名为RGBUIColor(red:green:blue)的函数,该函数会返回使用这些参数创建的UIColor对象。我们会使用Swift语言,并且使用Carthage作为依赖项的管理工具。我们的框架将会支持通过Carthage、CocoaPods或者git来使用。


  让我们开始吧!


  创建Xcode工程


  选择 File -> New -> Project


  在左侧的选择 iOS -> Framework & Library,右侧选择“Cocoa Touch Framework”。


  点击“下一步”,并填写选项提示。确保以及勾选了“Include Unit Tests”。


  选择工程保存的位置。


  不要勾选“Create Git repository on My Mac”,我们在后面手动进行设置。


  点击“创建”并且打开工程。


  选择File -> Save As Workspace并使用工程相同的名字保存到相同的目录中。之所以创建workspace是因为我们需要添加Carthage中的依赖作为子模块;使用Xcode


  编译他们的时候必须是在一个workspace中。


  选择File -> Close Project关闭工程。


  然后选择File -> Open打开*workspace*文件。


  Xcode左上角的scheme并选择“Manage Schemes”。我们需要确保sheme勾选了“shared”,以便能使用“Carthage”来构建工程。


  初始化git


  首先,切换到工程所在的目录。


  运行git init初始化空版本库。


  创建一个 .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和依赖项


  在工程的文件目录下创建一个名为Cartfile的文件以及运行时的依赖性。我们添加**Curry]**([链接)


  github "thoughtbot/Curry"


  创建一个名为Cartfile.private的文件。它会负责私有的一些依赖就像我们的测试框架一样。我们使用Quick和Nimble。


  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添加到工作区。你可以使用直接拖拽到项目的工作区。


  添加完结束后:


  链接运行时依赖


  在工作区的导航栏选择”RGB” ,然后在中间选择”RGB”目标,进而选择”Build Phases”,展开”Link binary with libraries”。


  点击”+”然后选择Curry.framework框架的Curry-iOS。


  点击添加。


  链接开发依赖项


  在中间的工具栏选择”RGBTests”。


  使用上面一样的步骤,将”Quick”和”Nimble”框架添加到”Link binary with libraries”。


  当我们将依赖添加到两个目标的时候,Xcode会自动在”Build Settings”下添加”Framework Search Paths”。我们可以在”RGB”和”RGBTests”中移除,因为同处同一工作区, Xcode将他们本身的一部分。


  选择目标下的两个目标,选中”Build Settings”下的”Framework Search Paths”,然后按“退格键”删除。


  接下来,在导航栏选择”RGB”工程的时候,你就会看见下面you三个刚刚添加的三个框架。然后全选这三个框架,然后右击选择”New group from selection”然后将他们放到一个组里, 我将组命名为”Frameworks”。


  现在Carthage已经设置完成,接下来是CocoaPods。


  添加CocoaPods支持


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


  新建RGB.podspec文件。


  将下面的实例拷贝并复制到文件中(自行对照修改相应的部分)。


  使用项目的信息来设置那些选项。更多的选项详情链接,但是该工程中你所需要的那些选择如下。


  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://twitter.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文件,你可以看见一个默认的模版。她使用了@testable和XCTest(,但是接下来我们会作出一些调整。


  首先,我们会移除@testable,因为我们需要测试那些框架使用者可能调用的API接口。随着框架的增长,我们可能会需要@testable去测试那些不是作为公共接口暴露的部分;总的来说,就是我们想避免测试那些暴露给使用者的接口。这个特性在测试应用的时候会更加有效,而不是在框架测试中。


  来源于苹果关于测试部分的文档:


  伴随者可测试性,你系那种能够在Swift 2.0框架和应用中编写测试并且不需要要测试所有的internal和public部分。在XCTest目标而不是其他框架或者应用的测试代码中使用@testable import {ModuleName}。


  我们使用Quick和Nimble作测试。Quick提供以一个行为驱动类型的测试接口,与RSpec和Specta非常相近;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!"


最近开班 more>
  • Web前端开发
  • 软件测试
  • 软件测试预科班
  • AI大模型+全栈开发开班
  • 云原生精英班
  • 云网预科班
  • 开发课程基础班第三期
  • 开发课程基础班第二期
  • 开发课程基础班第五期
  • Java全栈
  • CISP
  • HCIP-cloud
  • HCIE-Datacom(HCIA,HCIP基础)
  • HCIP-Datacom(HCIA基础)
  • HCIA-Datacom(0基础)
  • HCIE-Datacom(HCIA,HCIP基础)
  • HCIP-Datacom(HCIA基础)
  • HCIA-Datacom(0基础)
  • OCP 19C
  • RHCA
  • 6月9日
  • 5月21日
  • 5月14日
  • 6月9日
  • 5月7日
  • 5月26日
  • 5月19日
  • 5月12日
  • 6月3日
  • 6月9日
  • 随时开课
  • 7月12日
  • 5月19日
  • 5月19日
  • 5月7日
  • 5月10日
  • 5月24日
  • 5月24日
  • 随时开课
  • 随时开课
    • 姓 名 :
    • 电 话 :
    • 课 程 :

技术交流群

  • Java大数据交流群560819979加入
  • Python技术交流群595083299加入
  • Oracle技术交流群595119011加入
  • Web前端技术交流群604697610加入
  • Huawei技术交流群482919361加入
  • Redhat技术交流群587875348加入
  • UI设计技术交流群511649801加入
  • Cisco技术交流群596886705加入
  • IT运维技术交流群605888381加入