Swift

カスとマイズerrorのlocalizedDescription

enum CustomizedError: LocalizedError { case unexpectedError case sessionNotExist var errorDescription: String? { switch self { case .unexpectedError: return "unexpected error" case .sessionNotExist: return "session not exist" } } }

現在のthreadはmain threadかのチェック

Thread.isMainThread

ラベル付きループ

Kotlin: outer@for (i in 1..5) { for (j in 1..5) { println("i: $i, j: $j") if (j == 3) { continue@outer } } } Swift: outer: for i in 1...5 { for j in 1...5 { print("i: \(i), j: \(j)") if j == 3 { continue outer } } }

Reduceの小技

let a = [1, 2, 3] let sum = a.reduce(0) { $0 + $1 } は更に簡略できます: let a = [1, 2, 3] let sum = a.reduce(0, +)

UIDocumentPickerViewControllerの'init(documentTypes:in:)' was deprecated in iOS 14.0 解決策

元々: let documentPicker = UIDocumentPickerViewController(documentTypes: ["public.json"], in: .import) 現在: let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.json])

'requestReview()' was deprecated in iOS 14.0 解決策

SKStoreReviewController.requestReview()を下記コードに変更する: if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene { SKStoreReviewController.requestReview(in: scene) } 関連文章: cecil-it.hatenadiary.com

Dictionaryのキー存在しない時デフォルトバリューを提供する

let dic = ["dog": 1, "cat": 2] print(dic["chicken", default: 0]) // outputは0

Indices

let array = ["A", "B", "C"] for i in array.indices { print(i, array[i]) } equals let array = ["A", "B", "C"] for i in 0..

Array(repeating, count)の罠

Array(repeating, count)はクラスを作成の時には使えない。 例えばArray(repeating: UIView(frame: .zero), count: 5)を書いた時実に作ったViewは一つだけ。五つのポインターは同じViewに指しているだけ。 正しいやり方は(0...4).map { _ in UIView(frame: .…

Content Hugging PriorityとContent Compression Resistance Priority

Content Hugging Priority:二つのコンテンツが並んで、十分なスペースがある場合、そのpriority高いやつはもっとタイトな形式で表示する。 例:textAのContent Hugging PriorityはtextBより大きい場合: Content Compression Resistance Priority:二つのコ…

frameとbounds

frameはsuperViewに対する位置、x, yはsuperViewによって変わる。 boundsはview自身に対する位置、x, yは常に0。 だからviewAのsubView viewBを作って、viewBはviewAを完全重合したい場合、viewB.frame = viewA.boundと書く。 因みに、viewを移動したり変形…

実用的なString Extension

SwiftのStringは色々な考慮上、便利なSubstring方法を提供されていない。LeetCodeをやる時Stringの問題が合うとかなり面倒くさい。下記のextensionをコピペーすれば大変助かる。 extension StringProtocol { subscript(_ offset: Int) -> Element { self[ind…

??の実行順序について

LeetCodeをやっている時バグを遭遇した。 dic[a] = dic[a] ?? 0 + 1 のようなコードを書いた時、dic[a]は常に1になってしまう。 原因は0 + 1はいつも先に実行される。 だから上記にコードは下記のように書かないといけない: dic[a] = (dic[a] ?? 0) + 1

実用的なBundle Extension for Jsonファイルロード

extension Bundle { func load<T: Codable>(from fileName: String) -> T? { guard let url = url(forResource: fileName, withExtension: "json") else { return nil } guard let data = try? Data(contentsOf: url) else { print("File \(fileName) does not exist.") </t:>…

実用的なFileManager Extension for Jsonファイルのセーブ/ロード

enum FileName: String { case pc case gameData } extension FileManager { func load<T: Codable>(from fileName: FileName) -> T? { let url = getDocumentsDirectory().appendingPathComponent(fileName.rawValue) guard let data = try? Data(contentsOf: url) else</t:>…

Optionalプロパティのdecode方法

例えばプロパティvar weapon: Weapon?をdecodeしよう場合、decodeIfPresentは便利です。書き方は下記です: weapon = try container.decodeIfPresent(Weapon.self, forKey: .weapon) 関連記事: cecil-it.hatenadiary.com

Proerty Wrapper @AppStorage

@AppStorage("name") private var name = "Cecil" こう書くと、name属性はUserDefaultsからデータを読み込む。またname属性を変更するとき、UserDefaultの値も更新する。

App Storeのアプリページに遷移して、レビュー画面を表示

guard let writeReviewURL = URL(string: "https://apps.apple.com/app/idXXXXXXXXXX?action=write-review") else { fatalError("Expected a valid URL") } UIApplication.shared.open(writeReviewURL, options: [:], completionHandler: nil)

Format String

let priceString = "$1" let formattedString = String(format: "Purchase colorful dice by %@", priceString) print(formattedString) >> Purchase colorful dice by $1 formatの中のPlaceholderについて、%@はString型の引数、%dはInt型の引数、%fはDoubl…

for ... in文の中にインデックスを取得する方法

for (index, player) in players.enumerated() { ... }

Dateから年、月、日の部分だけ取得

let calendar = Calendar(identifier: .gregorian) //西暦 let currentDate = Date() let currentYear = calendar.component(.year, from: currentDate) let currentMonth = calendar.component(.month, from: currentDate) let currentDay = calendar.compo…

DateFormatterを使ってDateをStringに変換

func formatDate(_ date: Date) -> String { let formatter = DateFormatter() formatter.dateStyle = .short formatter.timeStyle = .short return formatter.string(from: date) } dateStyleとtimeStyleはnone、short、medium、long、fullという選択肢があ…

Data型とString型の互換

String -> Data // その結果はData?型。 let data = "aaa".data(using: .utf8) Data -> String let str = String(data: someData, encoding: .utf8)

Timer

var timer: Timer! timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { (_) in self.perform() }) func perform() { // some process if XXX { // time to end the Timer timer.invalidate() } }

簡単なAlert機能

extension UIViewController { func alert(title: String, message: String) { let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) let alertAction = UIAlertAction(title: "OK", style: .default, handler…

特定頻度でユーザのレビューを要求する

import StoreKit func askUserToRate() { var gamePlayed = UserDefaults.standard.integer(forKey: "gamePlayed") gamePlayed += 1 UserDefaults.standard.set(gamePlayed, forKey: "gamePlayed") if gamePlayed % 10 == 0 { SKStoreReviewController.reque…