はじめに

本書について

こんにちは!Swift愛好会&Kotlin愛好会主催の@jollyjoesterです。本書を手に取っていただき、ありがとうございます。

本書はSwiftを愛するメンバーが集まるSwift愛好会とKotlinを愛するメンバーが集まるKotlin愛好会の有志メンバーがネタを持ち寄って作成した初の技術同人です。言語についての話にとどまらず、Swift/Kotlinに関連の深いプラットフォームやサービスについての話など多岐にわたるネタについて盛り込んでいます。

各章は独立しています。著者紹介でそれぞれの章の概要を紹介しますので、興味を持った章から読み進めてください。楽しんでいただけるととても嬉しいです。

著者紹介

@jollyjoester
Swift&Kotlin愛好会主催。第1章の「やさしいSwift 5入門」を担当。2019年3月にリリースされたばかりのSwift 5についてわかりやすく変わった部分をピックアップしてゆるふわに紹介します。
@entaku19890818
動くものを作るのが好き!iOS開発が楽しいので、必然的にSwift書くようになりました 。今回は去年1年間iOSアプリ開発をして、もしも僕が新しくアプリ作るとしたら...と考えて書きました。是非新しくiOS開発する方に読んでもらいたいです!経歴はインフラ->サーバーサイド->iOS/Androidアプリ開発。iOSの比重が大き目なので、今年はAndroid力もあげたい。
@lovee
「Closureを理解する」を担当します、Auto Layout絶対◯すマンです。現在株式会社ゆめみの福岡オフィスでiOSエンジニアの仕事をしながら、採用などの仕事も時々やっています。
@bannzai
SwiftでOSSを書くのが趣味です。スターくださいと言いすぎてスター乞食というあだ名まで付いています。「Monitoring file system」を担当。私が書いた Ocha という OSS を紹介します。スターください
@o_chicchi
Swift愛好会の運営をしています。第5章の「Raspberry Pi で、Swift を触ってみよう」を担当。try!Swift2019 の Workshop の「Swiftでハードウェアを始めよう」から、実際にワークショップで行なわれた内容を元に、Raspberry Pi 上での Swift の遊び方をご紹介します。
@sohichiro
iOSアプリエンジニアとしてお仕事させてもらっています。スマフォアプリは、iOSしか書かれへんで、と伝えていたのに、いつのまにかAndroidアプリを作ることになってました。今回はその時のことを「iOSエンジニアが突然Androidアプリを開発することになってしまった時に読む章」に書かせていただきました。
@tarumzu
バックエンド、インフラ、Androidの開発ができるフルスタックエンジニアです。最近はAndroid一辺倒で、ひたすらAndroid開発しています。今回は直近のAndroid開発で経験したRealm Cloudを皆様に紹介いたします。
@n_takehata
主にスマートフォンゲームのサーバーサイド開発を生業としているバックエンドエンジニアです。サーバーサイドKotlinを布教するべく、鋭意活動中。第8章の「Kotlinでサーバーサイド開発をしてみよう」を担当しています。
@panini
Kotlinエンジニア。SwiftやGolangも興味あり、業務では主にAndroid開発しています。第9章の「Easy Code Generation with KotlinPoet」を担当。KotlinPoetで簡単にメンテナンスしやすくコード生成出来る方法をご紹介します。
@burakon
ぶらこんと名乗ることはや15年。Swift愛好会の運営をしています。中卒で派遣社員の事務職->Objective-Cの職業訓練校->iOSアプリ開発エンジニア兼デザイナーというキャリアを持つ。現在は小・中学生にプログラミングを教える講師業の傍、フリーランスエンジニアをしています。最近の流行はもっぱらScratch!

第1章 やさしいSwift 5入門

1.1 はじめに

ドーモ!jollyjoesterです。ついにSwift 5がリリースされました。Swift 5は2019年3月にリリースされたばかりのSwiftの最新バージョンです。Swift 5にはABI安定化やStringの再実装、実行時のメモリへの排他アクセスの強制、動的に呼び出し可能な型のサポートなど、様々な進化が詰まっています。しかし、それらは理解するには難しいのと普通に実装している分には意識しなくていい部分が多かったりします。

本章では、Swift5で「書き方が変わった」、「新しい書き方ができるようになった」ようなわかりやすい部分をピックアップしてゆるふわに紹介していこうと思います。新しいSwift 5を楽しく使っていきましょう!なお、筆者はiOSアプリ開発者であり、検証はXcode10.2を用いています。

1.2 わかりやすい新機能

1.2.1 Raw Text

Swiftでは文字列を表すための区切り文字としてダブルクォーテーション(")を使用します。この文字列の中で特殊な文字を使うときはバックスラッシュ(\)を用いてエスケープをする必要があります。

例えば「Hello, Swift "5" has come!」というダブルクォーテーション入りの文字列を表示させたい場合、ソースコード上では下記のようにエスケープしなければなりません。

通常の文字列

print("Hello, Swift \"5\" has come!")

でももし文字列中にエスケープが必要な文字が多く含まれていたらとてもめんどくさいですよね?ということでSwift 5からRaw Text*1が導入されました。

[*1] SE-0200 Enhancing String Literals Delimiters to Support Raw Text

Raw Textは#を用いて下記のように記述します。

Raw Text

print(#"Hello, Swift "5" has come!"#)

Raw Textを用いるとエスケープの必要がなくなり、表示したい文字列そのままを指定することができるようになります。表示したい文字列をどこかからコピペしてくる必要がある場合などに便利ですね。特殊文字を多く扱う場合の多い正規表現を扱うときに特に便利そうです。エスケープめんどくせぇ!と思ったらRaw Textの出番と覚えておきましょう!

なお、Raw Textという仕組みは多くの他の言語にもある仕組みで、SwiftのRaw TextはRustのRaw Textの影響を受けているようです。

1.2.2 isMultiple

isMultiple(of:)というメソッドで整数がある数の倍数であるかどうかを判別できるようになりました。*2

[*2] SE-0225 Adding isMultiple to BinaryInteger

これまである整数が偶数か奇数かを判別するのに「2で割った余りが0か否か」で判別していた方も多いと思います。

2で割ったあまりで判定

let num = 3

if num % 2 == 0 {
    print("even")
} else {
    print("odd")
}

これが下記のように書けるようになります。

2の倍数かどうかで判定

let num = 3

if num.isMultiple(of: 2) {
    print("even")
} else {
    print("odd")
}

2の倍数だったら偶数、じゃなかったら奇数と1 step省いて書けるようになりました。ちなみにisMultiple(of:)の提案者は偶数奇数を判定するisEvenやisOddも提案していましたが、isMultiple(of:)のみが承認されたようです。

みんな大好きFizzBuzzも素直にかけます。

みんな大好きFizzBuzz

(1...100).forEach{
    switch $0 {
    case let x where x.isMultiple(of: 3*5):
        print("FizzBuzz")
    case let x where x.isMultiple(of: 3):
        print("Fizz")
    case let x where x.isMultiple(of: 5):
        print("Buzz")
    default:
        print($0)
    }
}

1.2.3 Unicode Scalar

一般的なテキスト処理と高度なテキスト処理の両方のユースケースをサポートするためにUnicode.scalar*3に様々なプロパティが追加されました。

[*3] SE-0211 Add Unicode Properties to Unicode.Scalar

例えばisEmojiというプロパティを使って文字列から絵文字だけを取り出すことができます。

絵文字だけを取り出す

let message = "Happy🎉birthday🎂"
message.unicodeScalars.filter { $0.properties.isEmoji }
// "🎉🎂" // 紙面作成の都合で印字されませんが、手元で試してみてください

他にもisLowercase, isUppercase, isDash, isQuotationMarkなど様々なプロパティがあるので遊んでみると面白いです。

1.2.4 Character Properties

前述のUnicode ScalarへのプロパティはUnicodeに詳しい人が高度な操作をするためのものでしたが、もうちょっとわかりやすいものについてはCharacterのプロパティ*4にも追加されています。

[*4] SE-0221 Character Properties

例えば文字が数字かどうか判定することができます。

文字が数字かどうか判定する

let char: Character = "3"
char.isNumber
// true

他にもisASCII, isWhitespaceなどが追加されています。

1.2.5 Range

RangeがCodableに適合しました*5。これまでString, Int, Doubleなどの標準ライブラリの型と、Date, Data, URLなどのFoundationの型、およびこれらの型を要素に持つOptional, Array, DictionaryがCodableに適合していましたがRangeも適合した結果、例えば下記のように年齢、身長、温度など一定の幅のある数値を扱う際に便利になりました。

rangeを含むstructをencodeする

struct Toy : Codable {
    let name: String
    let ageRange: Range<Int>
}

let car = Toy(name: "car", ageRange: Range(4...6))

let data = try! JSONEncoder().encode(car)
let json = String(data: data, encoding: .utf8)
// "{"name":"car","ageRange":[4,16]}"

[*5] SE-0239 Add Codable conformance to Range types

1.2.6 compactMapValues

compactMapValues*6はDictionaryの値の型変換やnilの除去ができるものです。

[*6] SE-0218 Introduce compactMapValues to Dictionary

理解のためにArrayのcompactMapから復習していきましょう。Arrayにはnilを取り除く操作であるcompactMapがあります。

compactMapでnilを取り除く

["1", "2", nil, "4", "5"].compactMap{ $0 }
// ["1", "2", "4", "5"]

これを利用して型変換を一括で行い、型変換に失敗したものは取り除いたArrayを得ることもできます。例えば下記は各要素をInt型に変換してできなかった要素は取り除いたArrayが得られます。

compactMapで型変換

["1", "2", "A", "4", "5"].compactMap{ Int($0) }
// [1, 2, 4, 5]
//  "A"はIntに型変換できないので取り除かれた

これのDictionary版がcompactMapValuesです。Dictionaryの値がnilである要素を取り除いたDictionaryを得ることができます。

compactMapValuesで値がnilの要素を取り除く

["kei": "6", "rei": "4", "rui": nil].compactMapValues{ $0 }
// ["rei": "4", "kei": "6"]

Dictionaryの値を型変換し、型変換できなかった要素を取り除いたDictionaryを得ます。

compactMapValuesで値を型変換

["kei": "6", "rei": "4", "rui": "baby"].compactMapValues{ Int($0) }
// ["kei": 6, "rei": 4]
// "baby"はIntに型変換できないので取り除かれた

なお、余談ですがcompactMapValuesに貢献したのは@d_dateさんという日本人です。Swiftにどうやって新機能を提案していくかに興味がある方は彼の発信する情報を追ってみると良いでしょう。

1.2.7 Result

Swiftの標準ライブラリにResult*7型が追加されました。

[*7] Add Result to the Standard Library

すごく雑に言うとResult型はOptional型の親戚です。Optional型は「値がある or nil」を表す型ですが、Result型は「成功 or 失敗」を表す型です。

それぞれの宣言の必要な部分を抜き出して見てみると類似性を感じ取れます。

Optional

enum Optional<Wrapped> {
    case none
    case some(Wrapped)
}

Result

enum Result<Success, Failure> where Failure : Error {
    case success(Success)
    case failure(Failure)
}

Resultは特に非同期処理におけるエラーハンドリングに用います。

例えばResult型を返す処理があったとして

Resultを返す処理

func someMethod() -> Result<Data, Error>

下記のようにエラーハンドリングします。

Resultでエラーハンドリング

switch someMethod() {
  case .success(let data):
    // 成功:dataを用いる処理
  case .failure(let error):
    // 失敗:エラーハンドリング
}

1.3 より深く知るために

いくつかパッと試してわかりやすい機能を中心にSwift 5の新機能を紹介しました。もしこの中で1つでも興味がわいた機能があったのであればぜひ「Swift Programming Language Evolution」*8を覗いてみてください。「どうしてその機能を追加したいと思ったのか?」「その機能を追加する価値はどのようなものか?」「どのように設計して追加すると良いか?」などSwiftに機能が追加されていく様がリアルに感じられます。理解するのはだいぶ難しいですが、きっとSwiftをより楽しめるようになるでしょう。

それでは楽しいSwift Lifeを!

試し読みはここまでです。
この続きは、製品版でお楽しみください。