最近のプログラマーで、同じ言語で生涯終わるなんてことは稀ではないでしょうか。
kotlin/AndroidJavaやった後に感覚をすぐに取り戻すための必須メモ。
guard
アンラップした変数をスコープ外で利用、またnilチェックのように使う
ここでguardするのはnullを許容する?マークをつけるオプショナル型になります。
上記でrealmはスコープ外でも使えるのが特徴です。
1 2 3 4 5 6 |
guard let realm = self.realm() else { return } try! realm.write { // realmを使ったなんらかの処理 } |
上記でrealmはスコープ外でも使えるのが特徴です。
Codable
Codableなプロパティで構成されていればCodableとなる
String, Int, Double, Date, Data, URLは既にCodable
(Array, Dictionary, Optionalも同様)
String, Int, Double, Date, Data, URLは既にCodable
(Array, Dictionary, Optionalも同様)
codable1
1 2 3 4 5 6 7 8 9 10 |
import Foundation struct Coordinate: Codable { var lat: Double var lon: Double enum CodingKeys: String, CodingKey { case lat = "latitude" case lon = "longitude" } } let coordinate = try! JSONEncoder().encode(Coordinate(lat: 0, lon: 0)) |
enum
非常に便利
・イニシャライザ
・caseに引数を渡せる
・関数が使える
・イニシャライザ
・caseに引数を渡せる
・関数が使える
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
enum Lang { case Jp case En init(){ self = .En } } enum Fruits { //型は使わない case apple(price: Int) case orange(price: Int) //関数が利用できる func priceString(lang: Lang) -> String { switch self { case .apple(let price): return lang == .Jp ? "りんごは\(price)円" : "Apple is $\(price)" case .orange(let price): return lang == .Jp ? "みかん\(price)円" : "Orange is $\(price)" } } } var lang = Lang() override func viewDidLoad() { super.viewDidLoad() print("fruits: \(Fruits.apple(price: 100).priceString(lang: lang))") print("fruits: \(Fruits.orange(price: 150).priceString(lang: lang))") } |
extension
クラス、構造体、列挙体などを拡張します。
Objective-Cのカテゴリより便利ですっきり。
またクラスの継承で同じクラスを拡張することが出来ます。
1.クロージャーを繰り返す拡張例
2.プロパティを拡張する例
3.whereで制約をつける
4.プロトコルの拡張
大人数で作成する場合にはプロトコルで制約をつけることがよくあります
元を変更せずに拡張することが出来ます。
5.型の定義を分割する
Objective-Cのカテゴリより便利ですっきり。
またクラスの継承で同じクラスを拡張することが出来ます。
1.クロージャーを繰り返す拡張例
1 2 3 4 5 6 7 8 |
extension Int { func times(closure:() -> Void) { (0..<self).forEach{_ in closure() } } } 5.times{ print("Excute Closure") |
1 2 3 4 5 6 |
extension String { var localized: String { return NSLocalizedString(self, comment: self) } } "Hello".localized |
1 2 3 4 5 6 |
extension Array where Element == Int { func sum() -> Int { return reduce(0, +) } } [1,2,3].sum() |
大人数で作成する場合にはプロトコルで制約をつけることがよくあります
元を変更せずに拡張することが出来ます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
struct Adult: User { var name: String var email: String var age: Int } protocol User: Codable { var name: String { get } var email: String { get } var age: Int { get } } extension User { var json: Codable { guard let str = try! String(data: JSONEncoder().encode(self), encoding: .utf8) else { return "none" } return str } } let adult = Adult(name: "太郎", email: "taro@gmail.com", age: 20) print(adult.json) |
1 2 3 4 5 6 7 8 9 10 |
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() } } extension ViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 1 } } |
タプル
型が違う値をまとめられます。
メソッドの戻り値やSwiftLintで引数が多くひっかかる場合などに便利。
メソッドの戻り値やSwiftLintで引数が多くひっかかる場合などに便利。
1 |
var returnUser = ("Taro", 14, true) |
switch
タプル
範囲
条件
1 2 3 4 5 6 7 8 9 |
let month = 12 let day = 24 let date = (month, day) switch date { case (12,24): print("クリスマスイブ") case (12,25): print("クリスマス") case (1,1): print("元旦") default : break } |
1 2 3 4 5 6 7 |
let value = 2.4 switch value { case 0..<100: print("範囲内") default: print("範囲外") } |
1 2 3 4 5 6 7 |
let club = "grampus" switch club { case "grampus", "urawa": print("ユニフォーム色かぶり") default: print("例外") } |
1 2 3 4 5 6 7 |
let location = (20, 60) switch location { case (let x, let y) where x == 20 && y == 44: print("敵が出現") default: print("通常") } |
for/array/dictionary
・filter
文字通り条件指定して取り出したいときに便利
Dictionaryの場合の戻り値に注意
(swift3) Dictionaryでなくタプルで返却される
(swift4) Dictionaryで返却される
・map
要素に処理を加えたいときに便利
[3,5,7,9,11]
・reduce
要素の集計などに便利
reduceの引数0は初期値、sumは15になる。.reduce(0, combine: *)などcombineをクロージャでなく*,+などにすることも可能
組み合わせて使うと効果を発揮
for文で書いたほうが速いが数千件の簡単な処理でミリ秒の差程度なので、よっぽでなければ気にせず見やすいほうがよい。
・flatMap
2重の配列を1重にしたり、nilを除去します。
・for-in / forEach
for 変数 in 開始値 … 終了値
[1.2.3].forEach{ $0 }
・set
論理積が使えるのがメリットかな?
・array/dictionary
初期化について
・zip
2つの配列から辞書を作成
[“Grape”: 40, “Orange”: 30, “Apple”: 100]
・merge
文字通りマージできます。
文字通り条件指定して取り出したいときに便利
1 2 3 4 |
let dict = ["炭水化物": ["もち", "白米", "マーマレード"], "タンパク質": ["肉", "卵","大豆"]] let filtered = dict.filter { $0.key.contains("炭水化物") } |
(swift3) Dictionaryでなくタプルで返却される
(swift4) Dictionaryで返却される
・map
要素に処理を加えたいときに便利
1 2 |
let src = [1,2,3,4,5] let dest = src.map { $0 * 2 + 1 } |
要素の集計などに便利
1 2 3 |
let sum = [1, 2, 3, 4, 5].reduce(0) { res, num in return res + num } |
組み合わせて使うと効果を発揮
1 2 |
let info = ["Tokyo":14.0, "Osaka":17.0, "Aichi":15.0] let avr = info.map { 1.8 * $0.1 + 32 } .reduce(0, combine: +) / Double(info.count) |
・flatMap
2重の配列を1重にしたり、nilを除去します。
1 2 3 4 5 |
[[1, 2], [3]].flatMap { $0 } → [1, 2, 3] mapとの比較 [[1, 2], [3]].map { $0 } → [[1, 2], [3]] |
for 変数 in 開始値 … 終了値
[1.2.3].forEach{ $0 }
・set
論理積が使えるのがメリットかな?
・array/dictionary
初期化について
1 2 |
let fruits = ["Apple", "Orange", "Grape"] fruits.append("Pine") |
2つの配列から辞書を作成
1 2 3 4 |
let names = ["Apple", "Orange", "Grape"] let price = [100, 30, 40] let zipValue = zip(names, count) let dict = Dictionary(uniqueKeysWithValues: zipValue) |
文字通りマージできます。
1 2 3 |
var cart = [🍌: 1, 🍇: 2] let otherCart = [🍌: 2, 🍇: 3] cart.merge(otherCart, uniquingKeysWith: +) |
closureなどのweak/@escaping
クロージャーなどでcompletionHandlerで非同期処理などする場合に、処理待ちされません。
そんなときはスコープから退避する@escapingをつけます。
asyncMethod({
self.isFinish = true
})
そんなときはスコープから退避する@escapingをつけます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
func asyncMethod(completion: @escaping () -> Void) { 非同期処理{ completionHandler() } } 循環参照=たとえばクラスAとクラスBがお互いがインスタンスを強参照してしまうような状態。メモリーリークの代名詞w @IBOutletのものにはweakをつけましょう(特別なことしない場合は問題ない気がしますが) クロージャーのよくあるパターン <pre class="lang:default decode:true ">class Com { func send(success:((Void) -> Void)?) { success?() } } class ClassA { var com = Com() func sendData() { com.send({[weak self] () -> Void in if let _self = self { // 処理 } }) } } |
self.isFinish = true
})
lazy
値が代入されたときに初期化される
1 |
lazy var value: Int |
struct
クラスとほぼ同じstructは値型であるとして使い分ける
継承が関係ある場合はクラス
継承が関係ある場合はクラス
getter/setter
通常のgetter/setterに差はないと思いますが、入力時に他の処理をさせたいだけであればwillSetやdidSetを使う
アクセスコントロール
準備中
protocol
準備中
命名規則
準備中
よく使うライブラリ
・alamfire
・RxSwift
・Realm
・SwiftLint
・RxSwift
・Realm
・SwiftLint