1. 程式人生 > >使用Go語言開發iOS應用(Swift版)

使用Go語言開發iOS應用(Swift版)

http://www.ituring.com.cn/article/215762

本文加上讀者對Go語言和Swift語言都有一定了解, 但是對二者混合使用不瞭解的同學.

本教程是基於一個真實上架的iOS應用做的簡單的總結。

我們先看看執行效果:

掃碼安裝:

野雞醫院 掃碼安裝

背景

Go語言是Google公司於2010年開源的一個面向網路服務和多併發環境的程式語言,特點是簡單。 但是因為簡單,也就只能實現90%的效能,這是Go語言的最大優點,因為 少即是多 的道理不是每個人都能領悟的。

Swift是Apple公司於2014年釋出的用來替代ObjectiveC的語言,主要面向iOS和OS X上的介面程式開發。 當然用swift來開發伺服器也是大家關注的一個領域,作者看好在不遠的將來Swift將逐步替代C++和Rust語言。

Go語言和Swift語言本來是風馬牛不相及的兩個語言,為何非一定要整到一起呢? 原因很簡單,因為作者是一個Go粉,同時也算是半個Swift粉;想試水iOS開發,但是實在是受不了ObjectiveC的裹腳布語法。

補充下:本人雖然不喜歡ObjectiveC的語法,但是覺得ObjectiveC的runtime還是很強悍的。 理論上,基於ObjectiveC的runtime,可以用任何流行的程式語言來開發iOS應用,RubyMotion就是一個例子。

其實,現在流行的絕大部分語言都有一個交集,就是c語言相容的二進位制介面。 所以說,C++流行並不是C++多厲害,而是它選擇幾本無縫相容了C語言的規範。

但是,完全相容C語言的規範也有缺點,就是語言本身無法自由地發展,因為很多地方會受到C語言程式設計模型的限制。 C++和ObjectiveC是兩個比較有代表的例子。

所以說,Swift一出世就相容C語言的二進位制介面規範,同時抱緊了ObjectiveC的runtime大腿,而去自己確實有很大優秀的特性。

但是,我們這裡暫時不關心Swift和ObjectiveC的混合程式設計,我們只關注作為ObjectiveC子集的C語言如何與Swift混合程式設計。

Swift呼叫C函式

Swift呼叫C函式的方法有多種:通過ObjectiveC橋接呼叫和直接呼叫。其實兩者的原理是一樣的,我個人跟喜歡選擇最直接也最暴力的直接呼叫C函式的方式。

比如有一個C函式:

#include<stdio.h>void getInput(int*output){
    scanf("%i", output);}

生成一個橋接的標頭檔案xxx-Bridging-Header.h,裡面包含c函式規格說明:

void getInput(int*output);

swift就可以直接使用了:

importFoundationvar output:CInt=0
getInput(&output)

println(output)

如果不用橋接檔案,可以在swift中宣告一個Swift函式,對應C函式:

@_silgen_name("getInput") func getInput_swift(query:UnsafePointer<CInt>)

為了明確區分C函式和swift函式,我們將getInput重新宣告為getInput_swift,使用方法和前面一樣:

importFoundationvar output:CInt=0
getInput_swift(&output)

println(output)

Swift中如何管理c返回的記憶體

Swift語言本身是自帶ARC的,使用者很少直接關注記憶體問題。但是C函式如果返回記憶體到Swift空間, Swift的ARC是無效的,需要手工釋放C記憶體。

假設我們自己用C語言實現了一個字串克隆的函式:

char*MyStrDup(char* s){return strdup(s);}

在swift中可以這樣使用:

@_silgen_name("MyStrDup")
func MyStrDup_swift(query:UnsafePointer<CChar>)->UnsafeMutablePointer<CChar>

let p =MyStrDup_swift("hello swift-c!")
let s =String.fromCString(p)!
p.dealloc(1)

使用String.fromCString(p)!從C字串構建一個swift字串,然後手工呼叫p.dealloc(1)釋放c字串記憶體空間。

函式呼叫和記憶體管理是跨語言程式設計中最重要的兩個基礎問題,目前已久初步可以工作了。

Go語言匯出C靜態庫

Go語言提供了一個cgo的工具,用於Go語言和C語言互動。這是Go語言使用C語言的一個例子:

package main

//#include <stdio.h>import"C"

func main(){
    C.puts(C.CString("abc"))}

既然要互動,自然會涉及到C語言回撥Go語言函式的情形。為此,cgo提供了一個export註釋命令, 用於生成Go語言函式對應的C語言函式:

//export MyStrDup
func MyStrDup(s *C.char)*C.char{return C.strdup(s)}

MyStrDup指定的名字必須和Go函式名字一致,函式的引數最後是C語言支援的型別。

現在,我們就得到了用Go語言實現的MyStrDup函式,使用方法和前面的C語言實現的MyStrDup是一樣的。

和引用C語言函式庫遇到的問題一樣,我們如何在工程中引用這些C程式碼或Go程式碼實現的函式呢?

答案還是來自C語言:將程式碼構建為C靜態庫或者C動態庫,然後將靜態庫或動態庫匯入Swift工程。

但是,對於iOS來說,構建C靜態庫或者C動態庫的過程要麻煩(使用xcode也只是隱藏了構建的具體步驟)。

因為,iOS涉及到多種CPU架構:模擬器的x86、4s的32位arm、5s以後的64位arm,64位arm中還有不同當版本...

這是C靜態庫或者C動態庫構建始終都要面對的問題。

交叉構建的引數

Go1.6之後增加了構建C靜態庫的支援,交叉編譯也非常簡單,只需要設定好GOARCHGOOS就行。

因為,iOS的GOOS只有Darwin一種型別,我們只需要設定GOARCH就可以了。

要構建C靜態庫,我們需要將上面的MyStrDup實現放到一個main包中:

package main

//#include <string.h>import"C"

func main(){//}//export MyStrDup
func MyStrDup(s *C.char)*C.char{return C.strdup(s)}

main包中的main函式不會被執行,但是init函式依然有效。

使用下面的命令就可以構建當前系統的c靜態庫:

go build -buildmode=c-archive

要交叉編譯iOS可用的c靜態庫,我們需要先設定GOARCH,同時開啟cgo特性(交叉編譯時,cgo預設是關閉的)。

下面是構建針對模擬器的x86/amd64型別的C靜態庫:

export CGO_ENABLED=1export GOARCH=amd64

go build -buildmode=c-archive -o libmystrdup_amd64.a

我們使用-o引數指定了輸出的靜態庫檔名。構建命令同時還會生成一個頭檔案(可能叫libmystrdup_386.h), 我們沒有用到這個標頭檔案,直接刪除掉就可以。

下面是構建針對模擬器的x86/386型別的C靜態庫:

export CGO_ENABLED=1export GOARCH=386

go build -buildmode=c-archive -o libmystrdup_386.a

在構建x86/386型別的C靜態庫時可能會有一些link錯誤,我們暫時先用以下方法迴避。

建立一個patch_386.go檔案:

// Copyright 2016 <chaishushan{AT}gmail.com>. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// 針對iOS模擬器link時缺少的函式// 屬於臨時解決方案package main

/*
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

size_t fwrite$UNIX2003(const void* a, size_t b, size_t c, FILE* d) {
    return fwrite(a, b, c, d);
}

char* strerror$UNIX2003(int errnum) {
    return strerror(errnum);
}

time_t mktime$UNIX2003(struct tm * a) {
    return mktime(a);
}
double strtod$UNIX2003(const char * a, char ** b) {
    return strtod(a, b);
}

int setenv$UNIX2003(const char* envname, const char* envval, int overwrite) {
    return setenv(envname, envval, overwrite);
}
int unsetenv$UNIX2003(const char* name) {
    return unsetenv(name);
}

*/import"C"

當然,還是會有一些警告出現,暫時忽略它們。

構建多cpu型別的靜態庫

然後,將C靜態庫加入到ios的xcode工程檔案就可以了。

x86構建是比較簡單的,因為我們可以預設使用本地的構建命令。 但是,如果要構建arm的靜態庫,則需要先配置好構建環境。

我從Go程式碼中扣出了一個clangwrap.sh指令碼(好像是在$GOROOT/misci/ios目錄):

#!/bin/sh# This uses the latest available iOS SDK, which is recommended.# To select a specific SDK, run 'xcodebuild -showsdks'# to see the available SDKs and replace iphoneos with one of them.
SDK=iphoneos
SDK_PATH=`xcrun --sdk $SDK --show-sdk-path`export IPHONEOS_DEPLOYMENT_TARGET=7.0# cmd/cgo doesn't support llvm-gcc-4.2, so we have to use clang.
CLANG=`xcrun --sdk $SDK --find clang`if["$GOARCH"=="arm"];then
    CLANGARCH="armv7"elif["$GOARCH"=="arm64"];then
    CLANGARCH="arm64"else
    echo "unknown GOARCH=$GOARCH">&2exit1fiexec $CLANG -arch $CLANGARCH -isysroot $SDK_PATH "[email protected]"

裡面比較重要的是IPHONEOS_DEPLOYMENT_TARGET環境變數,這裡意思是目標最低支援ios7.0系統。

構建arm64環境的靜態庫:

export CGO_ENABLED=1export GOARCH=arm64
export CC=$PWD/clangwrap.sh
export CXX=$PWD/clangwrap.sh

go build -buildmode=c-archive -o libmystrdup_arm64.a

構建armv7環境的靜態庫:

export CGO_ENABLED=1export GOARCH=arm
export GOARM=7export CC=$PWD/clangwrap.sh
export CXX=$PWD/clangwrap.sh

go build -buildmode=c-archive -o libmystrdup_armv7.a

然後我們用lipo命令將以上這些不同的靜態庫打包到一個靜態庫中:

lipo libmystrdup_386.a libmystrdup_adm64.a libmystrdup_arm64.a libmystrdup_armv7.a -create -output libmystrdup.a

這樣的話,只要引入一個靜態庫就可以支援不同cpu型別的目標了。

總結

毛主席教導我們:要在戰爭中學習戰爭。

野雞醫院 這個app是作者第一個iOS應用,這篇教程也是在iOS開發過程逐步學習總結的結果。 裡面肯定有很多描述不準確的地方,作者歡迎任何不同意見或建議。

完整的例子:


相關推薦

使用Go語言開發iOS應用(Swift)

http://www.ituring.com.cn/article/215762 本文加上讀者對Go語言和Swift語言都有一定了解, 但是對二者混合使用不瞭解的同學. 本教程是基於一個真實上架的iOS應用做的簡單的總結。 我們先看看執行效果: 掃碼安裝:

Swift 語言開發 iOS 應用程式的利弊

目前全球共有超過 7 億臺 iPhone 處於活躍狀態,這造就了 iOS 作為全球第二大移動裝置平臺的狀態。雖然安卓系統的全球市場佔有率超過 iOS 系統,但在諸如美國、法國和英國的區域性市場中 iOS 系統仍然佔據主導地位。因此許多公司專注於 iOS 平臺進行軟體開發,因為

為什麼我堅持用Go語言做Web應用開發框架?

點選上方“CSDN”,選擇“置頂公眾號”關鍵時刻,第一時間送達!【CSDN編者按】很多情況下,企

go語言實現IOS OTA安裝應用

現在的IOS OTA安裝應用需要使用https才能安裝。 要使得伺服器支援https,伺服器必須要有https證書。證書可以同過購買獲得或者自己生成。 這裡我們使用自己生成的證書,使用自己生成的證書必須在iphone上手動安裝之後才能訪問https伺服器,否

CentOS6.8配置GO語言開發環境

應用程序 編程語言 處理器 谷歌 export 導讀Go語言是谷歌2009發布的第二款開源編程語言,Go語言專門針對多處理器系統應用程序的編程進行了優化,使用Go編譯的程序可以媲美C或C++代碼的速度,而且更加安全、支持並行進程。 鑒於越來越多的開源項目都采用Go為開發語言,本文介紹Lin

Go語言開發教程

googl lang 學習 概念 一個 人員 不能 環境安裝 服務 Go語言簡述興起:2009年Gogle發布的第二款開源編程語言特征:語法簡單:語法標準比較嚴格,適合開發人員短時間高效的服務端開發。並發模型:Goroutine是Go最顯著的特征,使用類協程的方式來處理並發

Go語言開發(一)、Go語言簡介

Go語言 簡介Go語言開發(一)、Go語言簡介 一、Go語言簡介 1、Go語言簡介 Go,全稱golang,是Google開發的一種靜態強類型、編譯型、並發型並具有垃圾回收功能的編程語言。 Go從2007年末由Robert Griesemer、Rob Pike、Ken Thompson(C語言發明者)主持開發

Go語言開發(二)、Go語言基礎

Go 語言 基礎 Go語言開發(二)、Go語言基礎 一、Go語言程序結構 Go語言程序基本結構如下:A、包聲明B、引入包C、函數D、變量E、語句 & 表達式F、註釋 package main //包聲明 import "fmt" //引入包 func main(){ //main函數

Go語言開發(三)、Go語言內置容器

第一個 支持 指向 ice 美國 p值 索引 叠代 指定大小 Go語言開發(三)、Go語言內置容器 一、Go語言數組 1、Go語言數組簡介 Go語言提供了數組類型的數據結構。數組是具有相同唯一類型的一組已編號且長度固定的數據項序列,類型可以是任意的原始類型例如×××、字符串

Go語言開發(四)、Go語言面向對象

name value code 對象 struct int() 初始 每一個 method Go語言開發(四)、Go語言面向對象 一、結構體和方法 1、結構體的定義 在結構體中可以為不同項定義不同的數據類型。結構體是由一系列具有相同類型或不同類型的數據構成的數據集合。結構體

Go語言開發(五)、Go語言面向接口

table ons 推導 arr ado default 被調用 等等 相關 Go語言開發(五)、Go語言面向接口 一、Duck Typing簡介 1、Duck Typing簡介 對於一門強類型的靜態語言來說,要想通過運行時多態來隔離變化,多個實現類就必須屬於同一類型體系,

Go語言開發(六)、Go語言閉包

技術 iad 調用 導致 nil \n 整體 不支持 變化 Go語言開發(六)、Go語言閉包 一、函數式編程 1、函數式編程簡介 函數式編程是一種編程模型,將計算機運算看作是數學中函數的計算,並且避免了狀態以及變量的概念。在面向對象思想產生前,函數式編程已經有數十年的歷史。

Go語言開發(七)、Go語言錯誤處理

pro package error 先進後出 goroutin cee 錯誤處理機制 避免 而是 Go語言開發(七)、Go語言錯誤處理 一、defer延遲函數 1、defer延遲函數簡介 defer在聲明時不會立即執行,而是在函數return後,再按照FILO(先進後出)的

windows下用sublime Text搭建go語言開發環境

使用 oot 輸出結果 test 格式 關於 .net 路徑 開發環境 1.安裝go 進入go 中文網:https://studygolang.com/dl 下載後安裝即可,有博客說以這種方式安裝go是不需要設置環境變量的(因為已經自動設置了),但經過嘗試發現這樣不行(設置

使用 Go 語言開發大型 MMORPG 遊戲服務器怎麽樣?(非常穩定、捕獲所有異常、非常適合從頭開始,但大公司已經有現成的C++框架、所以不會使用)

hive 有效 筆記 序列 優勢 nal 授權 登陸 RR 使用 Go 語言開發大型 MMORPG 遊戲服務器怎麽樣?和C Socket服務器比起來有什麽優劣?可行性怎麽樣? 從2013年起,經朋友推薦開始用Golang編寫遊戲登陸服務器, 配合C++做第三方平臺

Go語言開發(九)、Go語言並發編程

col 計數器 yield res 兩個 -c time 放心 還在 Go語言開發(九)、Go語言並發編程 一、goroutine簡介 1、並發與並行簡介 並行(parallel):指在同一時刻,有多條指令在多個處理器上同時執行。並發(concurrency):指在同一時刻

Go語言開發學習教程

教程 學習 cto 性能 開發 語言 內置 程序 com Go語言開發學習教程 Go語言開發學習教程目錄如下: Go語言開發(一)、Go語言簡介http://blog.51cto.com/9291927/2126775Go語言開發(二)、Go語言基礎http://blog.

使用Sublime text 3打造一個小巧但強大的Go語言開發IDE

details 交叉 download print please 建議 手動安裝 ida 裏的 版權聲明:歡迎轉載,轉載請註明出處! https://blog.csdn.net/iTaacy/article/details/76716049 使用Sublime tex

Go語言開發中MongoDB數據庫

urn import l數據庫 pkg selector 關系 示例 nec UNC 伴隨著移動端的興起,Nosql數據庫以其分布式設計和高性能等特點得到了廣泛的應該用,下面將介紹下Nosql中的mongoDB在Go語言中的應用,在開發前,有必要了解下基礎知識,mongo數

Go語言開發(十)、GoLand常用快捷鍵

查看源 關閉 打開文件 pro term 分享圖片 編輯模式 ctrl+h col Go語言開發(十)、GoLand常用快捷鍵 一、Goland快捷鍵設置 GoLand支持各種編輯器的快捷鍵映射:File->Settings->Keymap 二、GoLand