狠狠撸

狠狠撸Share a Scribd company logo
Swift おさらい
LINE Developer Meetup in Fukuoka #5
@taketin 2014/06/24
自己紹介
@taketin
LINE Fukuoka iOS developer
PHP, Ruby, Objective-C
(だいたい)毎週木曜19:30 ?
Fukuoka.swift よろしくお願いします
初めて買ったマック
Macintosh Performa LC630
Swift とは?
https://developer.apple.com/swift/
http://swift-lang.org/main/
https://developer.apple.com/swift/
http://swift-lang.org/main/
?
Swift is “Objective-C without the C”
? Swift言語の開発は2010年7月にAppleエンジニアの
個人プロジェクトから始まった
? 設計するにあたって影響を受けた言語は Objective-C、
Rust、Haskell、Ruby、Python、C#、 CLU等
via: http://jp.techcrunch.com/2014/06/05/20140604apples-new-programming-language-has-been-in-development-for-nearly-four-years/#Swift
特徴
? モダン
クロージャやタプル、ジェネリックプログラミング、 Optional型の採用。
via: 丑迟迟辫://箩补.飞颈办颈辫别诲颈补.辞谤驳/飞颈办颈/厂飞颈蹿迟冲(プログラミング言语)
特徴
? モダン
クロージャやタプル、ジェネリックプログラミング、 Optional型の採用。
? 安全
静的な型チェック、変数の初期化の強制、数値型のオーバーフローの検査、
自動参照カウント (ARC) によるメモリ管理など。
via: 丑迟迟辫://箩补.飞颈办颈辫别诲颈补.辞谤驳/飞颈办颈/厂飞颈蹿迟冲(プログラミング言语)
特徴
? モダン
クロージャやタプル、ジェネリックプログラミング、 Optional型の採用。
? 安全
静的な型チェック、変数の初期化の強制、数値型のオーバーフローの検査、
自動参照カウント (ARC) によるメモリ管理など。
? 高速
Objective-C より速い
via: 丑迟迟辫://箩补.飞颈办颈辫别诲颈补.辞谤驳/飞颈办颈/厂飞颈蹿迟冲(プログラミング言语)
特徴
? モダン
クロージャやタプル、ジェネリックプログラミング、 Optional型の採用。
? 安全
静的な型チェック、変数の初期化の強制、数値型のオーバーフローの検査、
自動参照カウント (ARC) によるメモリ管理など。
? 高速
Objective-C より速い
? インタラクティブ
コンパイラ言語だが、インタプリタとしてスクリプトを実行することも可能。対話実行環境 (REPL) 付属。
コードの実行結果をグラフィカルに確認しながら開発できる “Playgrounds” を実装。
via: 丑迟迟辫://箩补.飞颈办颈辫别诲颈补.辞谤驳/飞颈办颈/厂飞颈蹿迟冲(プログラミング言语)
では仕様を见ていきましょう
変数 (var)
var city: String = “Hakata”
変数、定数
変数 (var)
var city: String = “Hakata”
定数 (let)
let city: String = “Hakata”
city = “Tenjin” // error
変数、定数
変数 (var)
var city: String = “Hakata”
定数 (let)
let city: String = “Hakata”
city = “Tenjin” // error
型推論
var city = “Tenjin” // String 型と推論
変数、定数
変数名は日本語、ユニコード絵文字も
一部使用可。
var 街 = “博多”
変数、定数
暗黙の型変換はしない。
let label = "old"
let age = 36
String(age) + label
型変換
() で展開
var city = “Hakata”
“welcome to (city).”
変数展開
() で展開
var city = “Hakata”
“welcome to (city).”
式の評価もできる
var section = “Ekimae”
“welcome to (city + section).”
※ シングルクォートは使えない。
変数展開
nil 許容 (型の後ろに ? を付ける)
var optional: String = nil // error
Optional Value
nil 許容 (型の後ろに ? を付ける)
var optional: String = nil // error
var optional: String? = nil
通常、変数に nil を入れる事はできない。
Optional Value
var foo: String? = “bar” // {Some “bar”}
“指定された型の値”、もしくは “nil”
の2つの要素を持てるように曖昧な形に
「wrap」されている
という表現を使う。
Optional Value
「unwrap」する
var optional :String? = “foo” // {Some “foo”}
var notOptional = optional! // “foo”
ImplicitlyUnwrappedOptional
「unwrap」する
var optional :String? = “foo” // {Some “foo”}
var notOptional = optional! // “foo”
確実に nil では無いと判断できる場合のみ使用する。
値が nil の場合はランタイムエラーが発生する。
(fatal error: Can't unwrap Optional.None)
ImplicitlyUnwrappedOptional
特別な評価式
var optional :String? = “foo”
if let notOptional = optional {
println(“(notOptional) is not nil”)
} else {
println(“nil”)
}
optionalのnil判定を行い、代入しつつbool値を返す
ImplicitlyUnwrappedOptional
? は enum Optional<T>
! は struct ImplicitlyUnwrappedOptional<T>
のシンタックスシュガー
ImplicitlyUnwrappedOptional
? は enum Optional<T>
! は struct ImplicitlyUnwrappedOptional<T>
のシンタックスシュガー
? + Click で定義を見れるので、中身を
色々見て理解を深めましょう
ImplicitlyUnwrappedOptional
class Users {
class User {
var name: String = "taketin"
}
var user: User? = User()
}
OptionalChaining
class Users {
class User {
var name: String = "taketin"
}
var user: User? = User()
}
OptionalChaining
var users: Users? = Users()
if let name = users?.user?.name {
println(name) // “taketin”
} else {
println("error!")
}
class Users {
class User {
var name: String = "taketin"
}
var user: User? = nil
}
OptionalChaining
var users: Users? = Users()
if let name = users?.user?.name {
println(name)
} else {
println("error!") // error!
}
var response = (404, "NotFound")
Tuple
var response = (404, "NotFound")
response.0 // 404
response.1 // “NotFound”
Tuple
var response = (404, "NotFound")
response.0 // 404
response.1 // “NotFound”
// ラベル
response = (status:404, description:”NotFound”)
Tuple
var response = (404, "NotFound")
response.0 // 404
response.1 // “NotFound”
// ラベル
response = (status:404, description:”NotFound”)
response.status // 404
response.description // “NotFound”
Tuple
true or false
Bool値
true or false
YES or NO は無くなりました
Bool値
配列
var a = [1, 2, 3]
var b = String[]()
var c = Array<String>()
var d = Double[](count: 3, repeatedValue: 0.0)
// [0.0, 0.0, 0.0]
コレクション
配列イテレーション
var array = [1, 2, 3]
for value in array {
println(value)
}
コレクション
配列のコピー
var a = [1, 2, 3]
var b = a // [1, 2, 3] (参照渡し)
var a[0] = 9 // [9, 2, 3]
b // [9, 2, 3]
コレクション
配列のコピー
var a = [1, 2, 3]
var b = a // [1, 2, 3] (参照渡し)
a.append(4) // [1, 2, 3, 4]
b // [1, 2, 3]
コレクション
配列のコピー
var a = [1, 2, 3]
var b = a // [1, 2, 3] (参照渡し)
a.append(4) // [1, 2, 3, 4] (コピー作成)
b // [1, 2, 3]
配列長が変わると新しい配列を作る
コレクション
配列のコピー
var a = [1, 2, 3]
var b = a.copy() // 値渡し
コレクション
配列のコピー
var a = [1, 2, 3]
var b = a.copy() // 値渡し
または
var b = a
b.unshare() // 参照を切る
コレクション
配列範囲指定
var array = [1, 2, 3]
array[0..2] = [1] // [1, 3]
array[0...2] = [1] // [1]
コレクション
配列範囲指定
var array = [1, 2, 3]
array[0..2] = [1] // [1, 3]
array[0...2] = [1] // [1]
.. は未満 ... は以下(Rubyと逆なので注意)
コレクション
ディクショナリ
var a = Dictionary<Int, String>()
var b = [1:”foo”, 2:”bar”]
b[1] = nil // [2:”bar”]
コレクション
ディクショナリ
キーの型は hashable で無くてはならない。
String, Int, Double, Bool はデフォルトで
hashable (Hashable プロトコル継承)
コレクション
ディクショナリイテレーション
for (key, value) in dictionary {}
// キーのみ、値のみ
for key in dictionary.keys {}
for values in dictionary.values {}
コレクション
ディクショナリのコピー
var a = [1:”a”, 2:”b”]
var b = a // 値渡し
a[1] = “z” // [1:”z”, 2:”b”]
b // [1:”a”, 2:”b”]
コレクション
if文
if 条件式 {
/* Snip */
} else if 条件式 {
/* Snip */
}
コントロール
while文
while 条件式 {
/* Snip */
}
do {
/* Snip */
} while 条件式
コントロール
for文
for var index = 0; index < 5; index++ {
/* Snip */
}
for index in 0..5 {
/* Snip */
}
コントロール
switch文
let foo = "hoge"
switch foo {
case "bar":
println("bar")
case "baz", "hoge":
println("baz or hoge")
default:
println("other")
}
コントロール
switch文
基本 break 動作。
fallthrough を指定すると次の case も処理。
コントロール
switch文 いろいろなマッチング
case 1...3: // Range
case (_, 0): // tuple
case (let x, 0): // value bindings
case let (x, y) where x == y: // where
コントロール
enum Fukuoka {
case Tenjin
case Daimyo
case Hakata
case Nakasu
}
列挙型 (Enum)
enum Fukuoka {
case Tenjin
case Daimyo
case Hakata
case Nakasu
}
列挙型 (Enum)
var foo = Fukuoka.Tenjin
switch foo {
case .Tenjin
case .Daimyo
case .Hakata
case .Nakasu
}
enum Fukuoka {
case Tenjin
case Daimyo
case Hakata
case Nakasu
}
列挙型 (Enum)
var foo = Fukuoka.Tenjin
switch foo {
case .Tenjin
case .Daimyo
case .Hakata
}
switch must be exhaustive, consider adding a default clause
enum Rank: Int {
case One = 1
case Two, Three, Four
}
列挙型 (Enum)
enum Rank: Int {
case One = 1
case Two, Three, Four
}
var rank = Rank.Two // (Enum Value)
列挙型 (Enum)
enum Rank: Int {
case One = 1
case Two, Three, Four
}
var rank = Rank.Two // (Enum Value)
rank.toRaw() // 2
列挙型 (Enum)
enum Rank: Int {
case One = 1
case Two, Three, Four
}
var rank = Rank.Two // (Enum Value)
rank.toRaw() // 2
Rank.fromRaw(3) // (Enum Value)
列挙型 (Enum)
enum Fukuoka: String {
case Tenjin = "天神"
case Hakata = "博多"
}
var city = Fukuoka.Hakata
列挙型 (Enum)
enum Fukuoka: String {
case Tenjin = "天神"
case Hakata = "博多"
}
var city = Fukuoka.Hakata
city = .Tenjin // 型が分かっているので省略可能
列挙型 (Enum)
enum Fukuoka: String {
case Tenjin = "天神"
case Hakata = "博多"
func toKana() -> String {
switch self {
case .Tenjin: return "てんじん"
case .Hakata: return "はかた"
}
}
}
列挙型 (Enum)
enum Fukuoka: String {
case Tenjin = "天神"
case Hakata = "博多"
func toKana() -> String {
switch self {
case .Tenjin: return "てんじん"
case .Hakata: return "はかた"
}
}
}
列挙型 (Enum)
var city = Fukuoka.Tenjin // 天神
enum Fukuoka: String {
case Tenjin = "天神"
case Hakata = "博多"
func toKana() -> String {
switch self {
case .Tenjin: return "てんじん"
case .Hakata: return "はかた"
}
}
}
列挙型 (Enum)
var city = Fukuoka.Tenjin // 天神
city.toKana() // てんじん
Associated Values
enum APIResponse {
case Success(Int, String)
case Error(Int, String, NSError)
}
列挙型 (Enum)
Associated Values
enum APIResponse {
case Success(Int, String)
case Error(Int, String, NSError)
}
// if success
var res = APIResponse.Success(200, “OK”)
列挙型 (Enum)
Associated Values
enum APIResponse {
case Success(Int, String)
case Error(Int, String, NSError)
}
// if success
var res = APIResponse.Success(200, “OK”)
// if error
var res = APIResponse.Error(403, “Access denied”, error)
列挙型 (Enum)
Associated Values
switch res {
case let .Success(httpStatus, message):
… // 成功時処理
case let .Error(httpStatus, message, error):
… // エラー処理
}
列挙型 (Enum)
Associated Values
switch res {
case let .Success(httpStatus, message):
… // 成功時処理
case let .Error(httpStatus, message, error):
… // エラー処理
}
a.k.a
discriminated unions, tagged unions, or variants.
列挙型 (Enum)
func foo(bar: String, baz: Int) -> String {}
関数
func foo(bar: String, baz: Int) -> String {}
// キーワード指定可
func foo(aaa bar: String, bbb baz: Int) -> String {}
関数
func foo(bar: String, baz: Int) -> String {}
// キーワード指定可
func foo(aaa bar: String, bbb baz: Int) -> String {}
// 引数のデフォルト値指定可
func foo(bar: String, baz: Int = 1) -> String {}
関数
// 引数の可変長指定可 (Variadic Parameter)
func foo(bar: String, baz: Int...) -> String {}
関数
// 引数の可変長指定可 (Variadic Parameter)
func foo(bar: String, baz: Int...) -> String {}
// 引数の参照渡し (inoutラベル)
func swapValue(inout a: Int, inout b: Int) {}
swapValue(&a, &b)
関数
ネスト
func foo() -> Int {
func bar() {
func baz() {
}
baz()
}
bar()
}
foo()
関数
返り値が関数
func foo() -> ((Int, Int) -> String) {
func bar(number: Int, number2: Int) -> String {
return String(number + number2)
}
return bar
}
var bar = foo()
bar(1,2)
関数
返り値がタプル
func getTuple() -> (Double, Int, String) {
return (1.0, 2, "3")
}
var result = getTuple()
result.0 // 1.0
result.1 // 2
result.2 // "3"
関数
基本形
sort([“A”, “C”, “B”], { (s1: String, s2: String) -> Bool in
return s1 < s2
})
// [“A”, “B”, “C”]
クロージャ
型推論が効く
sort([“A”, “C”, “B”], { (s1: String, s2: String) -> Bool in
return s1 < s2
})
▼
sort([“A”, “C”, “B”], { s1, s2 in
return s1 < s2
})
クロージャ
式が1つだけの場合 return が省略できる
sort([“A”, “C”, “B”], { s1, s2 in
return s1 < s2
})
▼
sort([“A”, “C”, “B”], { s1, s2 in
s1 < s2
})
クロージャ
引数をプレースホルダで置換できる
sort([“A”, “C”, “B”], { s1, s2 in
s1 < s2
})
▼
sort([“A”, “C”, “B”], { $0 < $1 })
クロージャ
Operator Functions を使用する
sort([“A”, “C”, “B”], { $0 < $1 })
▼
sort([“A”, “C”, “B”], < )
クロージャ
Operator Functions を使用する
sort([“A”, “C”, “B”], { $0 < $1 })
▼
sort([“A”, “C”, “B”], < )
式によってはここまで簡略化できる
クロージャ
Trailing Closures
sort([“A”, “C”, “B”], { $0 < $1 })
▼
sort([“A”, “C”, “B”]) { $0 < $1 }
クロージャ
Trailing Closures
sort([“A”, “C”, “B”], { $0 < $1 })
▼
sort([“A”, “C”, “B”]) { $0 < $1 }
引数の最後がクロージャの場合、外出し記述可
クロージャ
Trailing Closures
sort([“A”, “C”, “B”], { $0 < $1 })
▼
sort([“A”, “C”, “B”]) { $0 < $1 }
引数の最後がクロージャの場合、外出し記述可
sort([“A”, “C”, “B”]) { < } ※これはエラーになった
クロージャ
blocks 内で self を使った場合の循環参照回避
// lang: Objective-C
__weak BlockOwner *weakSelf = self;
_block = ^() {
NSLog(@"name: %@", weakSelf.name);
};
クロージャ
blocks 内で self を使った場合の循環参照回避
// lang: Swift
self.aProperty = {
[unowned self] in // closure capture list
self.doSomething()
}
クロージャ
blocks 内で self を使った場合の循環参照回避
// lang: Swift
self.aProperty = {
[unowned self] in // closure capture list
self.doSomething()
}
引き続き注意が必要 ><
クロージャ
class Foo {
var bar: String
init(baz: Int) { // コンストラクタ
self.bar = baz // propertyイニシャライズ必須
}
func hoge(fuga: Int, piyo: Int) {}
deinit {} // デストラクタ
}
クラス
コンストラクタ
init() がコンストラクタ
引数がある場合 init(baz: Int) はインスタンス生成時に引数ラ
ベルを指定する必要あり
var foo = Foo(baz: 1)
クラス
コンストラクタ
init() がコンストラクタ
引数がある場合 init(baz: Int) はインスタンス生成時に引数ラ
ベルを指定する必要あり
var foo = Foo(baz: 1)
ただし、_ をラベルにする事で回避できる
init(_ bar:Int) // var foo = Foo(1)
クラス
コンビニエンスコンストラクタ
class Foo {
var bar:Int
init(baz: Int) {
self.bar = baz
}
func hoge(fuga:Int, piyo:Int) {}
convenience init() {
self.init(baz:0)
}
}
クラス
コンビニエンスコンストラクタ
var foo = Foo()
foo.bar // 0
コンストラクタ引数を省略する事ができる。その場合
convenience init 内に書かれた値で初期化される。
クラス
継承
class Foo : Bar {
}
クラス
継承
class Foo {
}
Objective-C と違い、基底クラスが無い場合は
継承を省略できる
クラス
メソッドオーバーライド
class Foo : Bar {
override func baz() {
}
}
クラス
メソッドオーバーライド
class Foo : Bar {
override func baz() {
}
}
スーパークラスと同名のメソッドを定義していても、
override が無ければ別メソッドとして認識される
クラス
コピー
var foo1 = FooClass()
foo1.bar // 10
var foo2 = foo1
foo2.bar // 10
クラス
コピー
var foo1 = FooClass()
foo1.bar // 10
var foo2 = foo1
foo2.bar // 10
foo1.bar = 50
foo2.bar // 50
クラス
コピー
var foo1 = FooClass()
foo1.bar // 10
var foo2 = foo1 // クラスは参照渡し
foo2.bar // 10
foo1.bar = 50
foo2.bar // 50
クラス
コピー
値渡しでコピーしたい場合は、
import Foundation して
NSCopying を継承。
copyWithZone() メソッドを自前で実装する。
(Objective-C と同じイメージ)
via: http://qiita.com/taketin@github/items/abcd2bea9e5888afa141
クラス
比較 (===)
var foo1 = FooClass()
var foo2 = FooClass()
foo1 === foo2 // false
クラス
比較 (===)
var foo1 = FooClass()
var foo2 = FooClass()
foo1 === foo2 // false
var foo3 = foo1
foo3 === foo1 // true
クラス
比較 (===)
var foo1 = FooClass()
var foo2 = FooClass()
foo1 === foo2 // false
var foo3 = foo1
foo3 === foo1 // true
インスタンスのアドレス比較を行う
クラス
Getter, Setter
class Foo {
var bar: Int {
get { return 10 }
set { self.baz = newValue }
}
var baz: Int = 0
}
クラス - プロパティ
Getter, Setter
class Foo {
var bar: Int {
get { return 10 }
set { self.baz = newValue }
}
var baz: Int = 0
}
setter は “newValue” で新しい値を参照できる
クラス - プロパティ
Getter, Setter
class Foo {
var bar: Int {
get { return 10 }
}
var baz: Int = 0
}
get のみ書く事で ReadOnly として定義できる
クラス - プロパティ
willSet, didSet
class Foo {
var bar:Int {
willSet {}
didSet {}
}
}
Objective-C の KVO のような動きができる
クラス - プロパティ
遅延ロード
class Foo {
@lazy var bar = SomeClass()
}
var foo = Foo() // ここでは bar 未初期化
foo.bar // ここで bar 初期化
クラス - プロパティ
Type Property Syntax
class Foo {
class var bar:Int {
return 1
}
}
Foo.bar // 1
クラス - プロパティ
class Foo {
var bar:Int = 5
init() {}
subscript(index: Int) -> Int {
return self.bar * index
}
}
Subscript
class Foo {
var bar:Int = 5
init() {}
subscript(index: Int) -> Int {
return self.bar * index
}
}
var foo = Foo();
foo[10] // 50 オブジェクトへの添字アクセスができる
Subscript
class Foo {
var bar:Int = 5
init() {}
subscript(index: Int) -> Int {
get { /* Snip */ }
set { /* Snip */ }
}
}
アクセスコントロールも可能
Subscript
イニシャライズ
struct Foo {
var bar: Int = 1
func baz() -> String {
return "test"
}
}
var foo = Foo()
構造体 (Structure)
イニシャライズ
struct Foo {
var bar: Int
func baz() -> String {
return "test"
}
}
var foo = Foo(bar: 1)
構造体 (Structure)
mutating
struct Foo {
var bar: Int = 1
func baz() {
bar = 10 // コンパイルエラー
}
}
構造体 (Structure)
mutating
struct Foo {
var bar: Int = 1
mutating func baz() {
bar = 10
}
}
構造体 (Structure)
static variable
struct Foo {
static var bar: Int = 1
}
Foo.bar // 1
構造体 (Structure)
コピー
var foo1 = Foo()
foo1.bar // 1
var foo2 = foo1
foo1.bar = 10
構造体 (Structure)
コピー
var foo1 = Foo()
foo1.bar // 1
var foo2 = foo1
foo1.bar = 10
foo2.bar // 1
構造体は値渡し(クラスは参照)
構造体 (Structure)
protocol FooProtocol {
var bar: String { get }
func baz() -> String
}
Protocol
protocol FooProtocol {
var bar: String { get }
func baz() -> String
}
class FooClass : FooProtocol {
var bar: String = “hoge”
func baz() -> String { /* Snip */ }
}
Protocol
protocol FooProtocol {
var bar: String { get set } // getter, setter 必須
func baz() -> String
}
class FooClass : FooProtocol {
var bar: String {
get { /* Snip */ } // set が無いのでコンパイルエラー
}
Protocol
protocol FooProtocol {
var bar: String
mutating func baz() -> String
}
struct FooStruct : FooProtocol {
var bar: String = “hoge”
mutating func baz() -> String { /* Snip */ }
}
Protocol
protocol FooProtocol {
}
protocol BarProtocol {
}
class FooClass : FooProtocol, BarProtocol {
/* Snip */
}
複数継承も可能
Protocol
extension String {
func twice() -> String {
return "(self) (self)"
}
}
Extention
extension String {
func twice() -> String {
return "(self) (self)"
}
}
var str = “hello”
str.twice() // “hello hello”
クラスだけでなく型などにも適用できる
Extention
extension String : FooProtocol {
func twice() -> String {
return "(self) (self)"
}
}
プロトコルの継承もできる
Extention
func Foo <任意の型> () {}
型の形式は UpperCamelCase。<HogeType> など。
短く <T> 等が慣習的に使われている。
Generics
型制約無し
func repeat<T>(item: T, times: Int) -> T[] {
var result = T[]()
for i in 0..times {
result += item
}
return result
}
Generics
型制約無し
func repeat<T>(item: T, times: Int) -> T[] {
var result = T[]()
for i in 0..times {
result += item
}
return result
}
repeat(“knock”, 4) // [“knock”, “knock”, “knock”, “knock”]
Generics
型制約無し
func repeat<T>(item: T, times: Int) -> T[] {
var result = T[]()
for i in 0..times {
result += item
}
return result
}
repeat(“knock”, 4) // [“knock”, “knock”, “knock”, “knock”]
repeat(10, 4) // [10, 10, 10, 10]
Generics
型制約有り
func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
Generics
型制約有り
func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
プロトコル継承の制約を定義できる
Generics
Any & AnyObject
var array : Any[] = ["1", 2, Foo()]
TypeCasting
Any & AnyObject
// 関数型以外なんでも入れる事ができる
var array : Any[] = ["1", 2, Foo()]
TypeCasting
Any & AnyObject
// 関数型以外なんでも入れる事ができる
var array : Any[] = ["1", 2, Foo()]
var array2 : AnyObject[] = [Foo(), Bar(), Baz()]
TypeCasting
Any & AnyObject
// 関数型以外なんでも入れる事ができる
var array : Any[] = ["1", 2, Foo()]
// クラスのインスタンスのみ入れる事ができる
var array2 : AnyObject[] = [Foo(), Bar(), Baz()]
TypeCasting
型チェック
var array : Any[] = ["1", 2, 3]
for obj in array {
if obj is Int {
println("(obj) is Int") // 2 is Int & 3 is Int
}
}
TypeCasting
ダウンキャスト
// obj には Base クラスのインスタンスが入っている
// Base を継承した Bar クラスが定義されている
let bar = obj as Bar // Bar クラス
TypeCasting
ダウンキャスト
// obj には Base クラスのインスタンスが入っている
// Base を継承した Bar クラスが定義されている
let bar = obj as Bar
もし obj に Bar へダウンキャストできないオブジェクトが入って
いたらランタイムエラー
TypeCasting
ダウンキャスト
// obj には Base クラスのインスタンスが入っている
// Base を継承した Bar クラスが定義されている
let bar = obj as? Bar
オプショナルで安全
TypeCasting
ダウンキャスト
for obj in array {
if obj is Bar {
let bar = obj as Bar
/* Snip */
}
}
TypeCasting
for obj in array {
if let bar = obj as? Bar {
/* Snip */
}
}
ダウンキャスト
for obj in array {
if obj is Bar {
let bar = obj as Bar
/* Snip */
}
}
TypeCasting
for obj in array {
if let bar = obj as? Bar {
/* Snip */
}
}
OptionalValue の評価式を使って、評価 > 代入が簡単に書ける
存在する演算子を拡張
@infix func + (left: String, right: Int) -> String {
return "(left) (right)"
}
Operator Functions
存在する演算子を拡張
@infix func + (left: String, right: Int) -> String {
return "(left) (right)"
}
“number” + 1 // “number 1”
Operator Functions
存在しない演算子を定義
@infix func +++ (left: String, right: Int) -> String {
return "(left) (right)"
}
“number” +++ 1
Operator Functions
存在しない演算子を定義
@infix func +++ (left: String, right: Int) -> String {
return "(left) (right)"
}
“number” +++ 1 // コンパイルエラー
Operator Functions
存在しない演算子を定義
operator infix +++ {}
@infix func +++ (left: String, right: Int) -> String {
return "(left) (right)"
}
“number” +++ 1 // “number 1”
Operator Functions
その他詳細は公式ドキュメントをご覧くだ
さい。
https://developer.apple.
com/library/prerelease/ios/documentation/swift/conceptual/swift_prog
ramming_language/
ドキュメントに見当たりません
おまけ:正規表現
えっ、、、
おまけ:正規表現
NSRegularExpression を利用して Perl ライクな
=~ 演算子を使えるようにするライブラリがあるの
でとりあえず利用すると良さそう。
https://github.com/kasei/SwiftRegex
おまけ:正規表現
“Namespacing is implicit in swift, all classes (etc) are implicitly
scoped by the module (Xcode target) they are in. no class
prefixes needed”
「Swiftにおいて名前空間は暗黙のうちに提供される。すべてのクラ
スはそのモジュール (Xcode上のターゲット)によって暗黙のうちに
スコープが制限される。クラスプレフィックスはもはや不要」
via: https://twitter.com/clattner_llvm/status/474730716941385729
おまけ:名前空間
アクセス修飾子 (private, public)
おまけ:今後の展望
アクセス修飾子 (private, public)
"We don't usually promise anything for the future, but in this
case we are making an exception. Swift will have access
control mechanisms."
「将来の約束は一般的にしてないんだけど、今回は例外。Swift
にはアクセス制限のための仕組みを追加予定です」
via: http://stackoverflow.com/questions/24003918/does-swift-have-access-modifiers
おまけ:今後の展望
CocoaPods
おまけ:今後の展望
CocoaPods
https://github.com/CocoaPods/CocoaPods/tree/swift
https://github.com/CocoaPods/CocoaPods/pull/2222
着々と進行中の様です。待ちましょう。
おまけ:今後の展望
汎用言語として公開してくれないかなー
おまけ:今後の希望
LINE Fukuoka では Swift なら誰にも負けないと
いうエンジニアさんを求めています!
更におまけ
福岡で一緒に LINE を育てていきましょう!
https://linefukuoka.co.jp/career/developer
更におまけ
ご清聴ありがとうございました。

More Related Content

厂飞颈蹿迟おさらい