swiftenvでSwiftのバージョンを管理する

swiftenvでSwiftのバージョンを管理する

f:id:moapp:20160602170720p:plain

Swift3.0の開発版が公開されてからSwiftの2系と3系の間のタイミングである今、iOSなどのアプリ開発ではSwiftの2系、Swift3の変更点の確認ではSwift3.0というような使い分けをする場面が出てくるかもしれません。

そのような時こそSwiftのバージョン管理をしてくれるswiftenvがオススメです。

Homebrewからswiftenvをインストールする

Macで簡単に設定をするためにHomebrewからインストールします、ターミナル上から下記コマンドを入力します。

brew install kylef/formulae/swiftenv

swiftenvのpathを設定する

インストールが完了したらswiftenvのパスを設定します、使ってるシェル環境に合わせて設定しましょう。

bash

~/.bash_profileの部分は環境によって変わると思うので、環境に合わせて~/.bashrcなり変更してください

echo 'if which swiftenv > /dev/null; then eval "$(swiftenv init -)"; fi' >> ~/.bash_profile

zsh

echo 'if which swiftenv > /dev/null; then eval "$(swiftenv init -)"; fi' >> ~/.zshrc

fish

echo 'status --is-interactive; and . (swiftenv init -|psub)' >> ~/.config/fish/config.fish

swiftenvを反映する

swiftenv側で設定してるSwiftを参照するように反映させます。

swiftenv rehash

swiftenvを動かしてみる

swiftenvコマンドを入力してヘルプが出れば設定が正常に完了になります、基本的にはpyenvrbenvと使い方は変わりません。

$ swiftenv 
Usage: swiftenv [--version] <command>

  version   Displays the current active Swift version
  versions  Lists all installed Swift versions
  global    Sets the global version of Swift
  local     Sets the local application-specific version of Swift
  install   Installs a version of Swift
  uninstall Uninstalls a specific Swift version
  rehash    Installs shims for Swift binaries

Visit https://swiftenv.fuller.li for more info.

現在の環境で設定されてるSwiftのバージョンを確認する

swiftenvで管理してるSwiftのバージョンのうち、設定してるバージョンを確認します。

systemというのがswiftenvで管理する前からインストールされているSwiftになります。

$ swiftenv version
system (set by /Users/__moai/.swiftenv/version)

swiftenvで管理してる複数のSwiftのバージョンを確認する

swiftenvで管理してるSwiftのバージョンの一覧を確認します。

下記のようにsnapshotのタグ名で管理されていることが分かります。

$ swiftenv versions
* system
  3.0-preview-1-SNAPSHOT-2016-05-31-a
  DEVELOPMENT-SNAPSHOT-2016-05-09-a
  2.2

設定するSwiftのバージョンを変更する

swiftenvでSwiftのバージョンを切り替える際は、localglobalという概念の2種類があります。

localがそのディレクトリ内だけでSwiftのバージョンを変えたい場合、globalが全てのディレクトリでSwiftのバージョンを変えたい場合に使い分けます。

まずはglobalでSwiftのバージョンを変更してみます。

swiftenv global 3.0-preview-1-SNAPSHOT-2016-05-31-a

Swiftのバージョンが変わったどうか確認します。

$ swift --version
Apple Swift version 3.0-dev (LLVM 3863c393d9, Clang d03752fe45, Swift e996f0c248)
Target: x86_64-apple-macosx10.9
$ swiftenv version
3.0-preview-1-SNAPSHOT-2016-05-31-a (set by /Users/__moai/.swift-version)

このようにSwiftから見ても、swiftenvから見てもバージョンを変更したことが確認できます。

それでは続いてlocalでSwiftのバージョンを変更してみます。

ここではhogeディレクトリを新しく作成し、その中でSwiftのバージョンをsystemに変更します。

mkdir hoge
cd hoge
swiftenv local system

ここで変わったことを確認します。

$ swift --version
Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.31)
Target: x86_64-apple-macosx10.9
$ swiftenv version
system (set by /Users/__moai/hoge/.swift-version)

Swiftのバージョンが先ほどと同じswiftenvを入れる前のSwiftのバージョンになっていることが確認できました。

仕組みとしてはlocalで切り替えたSwiftのバージョンは、ディレクトリ内に.swift-versionというファイルが作成されており、その中でSwiftのバージョンが記載されています。

なのでhogeディレクトリ内のSwiftのバージョンを再度globalのSwiftのバージョンに変更したい場合はこの.swift-versionを削除すれば反映されます。

rm .swift-version

おわりに

このようにSwiftのバージョン管理を楽にしてくれる便利なswiftenvの紹介でした。

みなさんもどんどんバージョンアップが進むSwiftの変更を追いかける際の便利な道具として是非試してみてください。

Swift3.0で文字列操作

Swift3.0で文字列操作

f:id:moapp:20160601182612p:plain

Swiftでは文字列周りの操作はFoundationのライブラリを使うことで簡単に操作することができます。

ですが今回はあえてFoundationを使わないで文字列の操作を一通り行うコードを乗せつつ説明していきます。

文字列同士を結合する

文字列の結合は単純に「+演算子を繋げるだけです。

"123" + "456" // -> "123456"

対象の文字列の配列から1つの文字列に集約する

文字列を配列から集約する場合はjoined(separator: String)関数を使用します。

["1", "2", "3", "4", "5", "6"].joined(separator: "") // -> "123456"

対象の文字列から指定の1文字の位置を検索する

対象の文字列をCharacterの配列として扱い、enumeratedで文字とインデックスを取るようにしておきます。

そして指定の1文字でfilterをかけて、最初にヒットしたインデックスの値を元にString.Indexの値として取得します。

この例では取得したString.Indexの値が取れてることを確認するためにsubscriptでアクセスできるかどうかを確認しています。

extension String {
    
    func index(character: Character) -> String.Index? {
        let index = self.characters.enumerated().filter { (idx, c) in c == character }.first?.0
        guard let offset = index else {
            return nil
        }
        return self.index(self.startIndex, offsetBy: offset)
    }
}

let string = "123456"
if let index = string.index(character: "3") {
    string[index] // -> "3"
}

対象の文字列から指定の文字列の範囲を検索する

対象の文字列が指定の文字列の先頭1文字を含んでいた場合に、一致したインデックスから指定の文字列の長さの数だけ終端のインデックスを取得しておきます。

先頭から終端のインデックスを元にRangeを用意して対象の文字列をスライスし指定の文字列と同じかどうかを比較します。

同じだった場合のみRangeを返します。

extension String {

    func range(string: String) -> Range<String.Index>? {
        guard let startIndex = self.index(character: string[string.startIndex]) else {
            return nil
        }
        
        guard let endIndex = self.index(startIndex, offsetBy: string.characters.count, limitedBy: self.endIndex) else {
            return nil
        }
        
        let range = startIndex..<endIndex
        if self[range] != string {
            return nil
        }
        
        return range
    }
}

let string = "123456"
if let range = string.range(string: "34") {
    string[range] // -> "34"
}

指定する1文字ごとに対象の文字列を分割する

対象の文字列をCharacterの配列として扱い、split(separator: String)関数を利用して分割しています。

extension String {

    func separatedComponents(separator: Character) -> [String] {
        return self.characters.split(separator: separator).map(String.init)
    }
}

"1,2,3,4,5,6".separatedComponents(separator: ",") 
// -> ["1", "2", "3", "4", "5", "6"]

指定する1文字を対象の文字列から取り除く

対象の文字列をCharacterの配列として扱い、指定する1文字でfilterをかけてもう一度文字列として集約をかけます。

extension String {
    
    func removed(character: Character) -> String {
        return self.characters.filter { $0 != character }.map { String($0) }.joined(separator: "")
    }
}

"1,2,3,4,5,6".removed(character: ",") // -> "123456"

指定する文字列を対象の文字列から取り除く

replaceSubrange(range: Range<String.Index>, with: String)を内部で再帰的に呼び出して文字列を取り除きます。

extension String {
    
    func removed(string: String) -> String {
        if let range = self.range(string: string) {
            var mutatingSelf = self
            mutatingSelf.replaceSubrange(range, with: "")
            return mutatingSelf.removed(string: string)
        }
        return self
    }
}

"1, 2, 3, 4, 5, 6".removed(string: ", ") // -> "123456"

Xcodeで開発版のSwift3.0を試してみた

XcodeでSwift3.0の開発版を動かす

f:id:moapp:20160531093401p:plain

Swiftが世に出てから2年経ち、オープンソース化されてから半年経とうとしています。

Swift3は今までの下位バージョンとの互換性を意識せず大幅な変更を加えており、ベースとなるProtocol名の一新、C言語のfor文のスタイル撤廃、カリー化の文法変更などがあり、よりモダンな言語として生まれ変わっています。

そしてSwift3以降の変更に関しては最小限の変更で留めてアップデートをしていくとのことで、Swift3から変更点を追いかけてもSwift4以降も十分に追いかけられるでしょう。

そこでMac OSXcodeを使って開発版のSwift3.0を動かしてみます。

Swift3.0を試す開発環境

Mac OSXcodeは現時点での最新で試しています。

Swift3.0のsnapshotをダウンロードする

Swift.orgからXcodeの最新版をダウンロードします。(現時点だとMay 9, 2016

snapshotをインストールする

ダウンロードしてきたpkgファイルをインストールしましょう。

f:id:moapp:20160531085909p:plain

Xcodeにsnapshotを反映させる

準備としてはこれだけであとはXcodeを開いてSwift3.0のsnapshotをXcode側に設定します。

Xcodeを起動して、メニューからXcode > Toolchainsを選択し先ほどインストールしたsnapshotを選択してください。

f:id:moapp:20160531090536p:plain

Swift3.0をXcodeで動かす

それではXcodeで動かすための環境ができたので、新しく変更されたカリー化の文法を試してみます。

func calclate(_ a: Int) -> (Int) -> Int {
    return { b in
        return a + b
    }
}

let calclator = calclate(3)
print(calclator(10))
print(calclator(14))

上記のコードをPlaygroundで動かそうとしたのですがsnapshotからだと動かないのか反応しなくなりました。

なので適当なプロジェクトを用意して、そこで動かします。

f:id:moapp:20160531091717p:plain

ちゃんとカリー化できてることが確認できてますね。

このように新しいバージョンのSwiftはこれだけの手順を踏めば試すことができます。

これからもどんどんよりよくなっていくSwiftを追いかけていきましょう。