20210428のSwiftに関する記事は11件です。

[SwiftUI]モディファイアとは(初学者向け)

モディファイアとは import SwiftUI struct ContentView: View { var body: some View { Text("Hello, Udemy") //以下.(ドット)で始まるコードがモディファイア .font(.title) .fontWeight(.medium) .foregroundColor(Color.blue) .padding() } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } 上記コードのように.(ドット)〜を付け足すことでUIを変更するものをモディファイアと呼びます。 今回の場合は、Text("Hello, Udemy")に対してモディファイアを適応しています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

既存のアプリのstoryboardを分割する方法。(storyboard reference)

0. はじめに こんな感じで、1つのstoryboardに複数のviewControllerが設置されているのは良くないので、これを分割することを考えます。おそらく実務とかでも分割するということで統一されているので、できるようになっておいて損はないはずです。 1. storyboard referenceを設置して、segueで接続 次のstoryboardファイルへの道しるべみたいなものです。 2. 新しくstoryboardファイルを作成する ここに分割する対象のviewControllerを設置します。storyboardフォルダ等を作成して、まとめておくと良いです。 3. 分割したいviewControllerを、新しく作成したstoryboardファイルにコピペ! 左のリストから選択すると楽です。 コピーして ペースト コピペが終わったら、元のViewControllerは削除しても大丈夫です。 4. identifierなど、その他諸々の設定 segueのidentifierを設定してください。 次に、最初に設置した、storyboard referenceのinspectorから、遷移したいviewControllerがあるstoryboardファイルを選択してください。storyboard referenceの見た目の少し変わるはずです。 さいごに、遷移する先のstoryboardファイルのviewcontrollerのinspectorから、is initial view controllerにチェックを入れてください。これは新しいstoryboardに遷移したとしても、その中のどのviewControllerに移ればよいかを、xcodeがわからないためです。 これでstoryboard referenceで遷移ができるようになりました! 5. 1-4を繰り返して、一つのstoryboardに一つのviewControllerが含まれるようにする。 これが完了すれば、だいぶスッキリして保守しやすくなるはずです。 何か質問あればコメントしてください!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

macのOpenCVで利用されるCameraのDevice Listの取得方法

こんなこと、ありませんか?解決できます! コードを変えていないのに、カメラが別のカメラに切り替わってしまう! チームメンバーの環境で試してもらうときに、独自定数 camera_device_index をいくつか試すように伝えないといけない! system_profiler -json SPCameraDataTypeを使えばデバイスリストを取得できると聞いたのに、異なるカメラに接続されてしまうケースが頻発! swiftスクリプトでデバイスリストを取得できます! 私が公開しているこのスクリプトで信頼できるリストがつくれます! 前提 macOS (私はmacOS 11.3) OpenCVのcv::VideoCaptureを利用している。 Capture API backendsにCAP_ANYかCAP_AVFOUNDATIONかCAP_FFMPEGを使っている。 仕組み macのcv::VideoCaptureはCapture API backendsに様々なものを利用できるようになっています。(リスト) 特殊な設定をしていなければmacではCAP_ANYにすると、CAP_AVFOUNDATIONかCAP_FFMPEGが選択されます。 Capture API backendsがどちらであったとしても、macでは最終的にはAVFoundationが使われてビデオキャプチャしています。ffmpegの場合、ffmpegのAVFoundationプラグインが利用されます。 したがって、camera_device_indexはAVFoundationのリストと整合すればよいのです。 AVFoundationのカメラデバイスリストの取得方法 残念ながら標準のコマンドは存在しないようですし、pythonやc++から直接使うには骨が折れます。 ですが、AVFoundationはswiftからなら非常に簡単に取得できます。 またmacではswiftを特殊なビルドなくスクリプトのように利用できます! swiftスクリプトでリストをつくりstdoutに出力しさえすれば、あとはpythonやC++からコマンド呼び出ししてstdoutを捕まえてあげればok SwiftでのAVFoundationのカメラリスト取得コード あまりにも簡単すぎで説明が必要ないですね。メソッドの詳細を知りたい人は検索すればAppleのページで詳しく説明してくれています。 import AVFoundation let discovery = AVCaptureDevice.DiscoverySession( deviceTypes: [ AVCaptureDevice.DeviceType.builtInWideAngleCamera, AVCaptureDevice.DeviceType.externalUnknown, ], mediaType: AVMediaType.video, position: AVCaptureDevice.Position.unspecified ) let devices = discovery.devices 所感 かなり振り回されました。この半年ひどくハマりました。チームメンバーにも迷惑を掛けたと思います。 結局、OpenCVのコードを追いかけて、ffmpegのコードを追いかけてやっとここまでたどり着きました。どちらもプラグインという概念で拡張しているためコードを追うのは一苦労です。cmakeやconfigureの引数でリンクするコードが変わってしまいます。 やっと安心してVideoCaptureを利用できそうです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

配列操作 swift

■配列のプロパティまとめ 概要 プロパティ 説明       要素の数 count 配列の中身の数を返す 先頭の要素 first 始めの要素を返す 最後の要素 last 最後の要素を返す 空か isEmpty 空の配列であればtrue,要素があればfalseを返す let a = ["りんご","ばなな","みかん"] print(a.count) //結果: 3 //注意 firstとlastは結果がoptional型で渡されるのでオプショナルバインディングする事 if let first = a.first { print(a.first) //結果: りんご } if let last = a.last { print(a.last) //結果: みかん } print(a.isEmpty) //結果: false ■配列のメソッド 概要 メソッド 説明      検索 firstIndex 指定した配列の中身の値のインデクス番号を返す 検索 lastIndex 指定した配列の中身の値のインデクス番号を返すfirstIndexとの違いは僕は謎ですw 部分列 prefix 先頭から数えた指定した個数分の配列を返す 部分列 suffix 末尾からつまり配列の後ろの要素から数えた指定した個数分の要素を返す 部分配列 dropFirst 指定した個数分の先頭要素を取り除いた要素を返す 部分配列 dropLast 指定した個数分の末尾要素から取り除いた要素を返す 追加 append 配列の末尾に値を付け加える 挿入 insert 指定した位置に値を挿入する 消去 remove 指定した位置の要素を消去する 消去 removeFirst 最初の要素を消去する 消去 removeLast 最後のの要素を消去する 消去 removeAll 要素を全て消去する 整列 sort 要素を決められた順番(昇順)に替える完全に固定でずっと変わる 整列 sorted 要素を決められた順番(昇順)に替えて返す 一時的に順番を変えたい時こっち ランダム randomElement 要素をランダムに返す シャッフル shuffle 要素をランダムに並び替えるずっと シャッフル shuffle 要素をランダムに並び替えた物を一時的に返す 逆順 revese 要素を元の配列と逆にするずっと 逆順 reversed 要素を元の配列に逆にした配列を返す var a = ["a","b","c","d"] a.firstIndex(of: "c") //2 a.lastIndex(of: "d") //3 a.prefix(2) // ["a","b"] a.suffix(2) // ["c","d"] a.dropFirst(3) // ["d"] a.dropLast(2) // ["a","b"] a.append("e") //["a","b","c","d","e"] a.insert("f", at: 0) //["f","a","b","c","d","e"] a.remove(at: 0) //["a","b","c","d"] fがなくなっている。 a.removeFirst() //["b","c","d"] aがなくなっている a.removeLast() //["b","c"] dがなくなっている a.removeAll() //[] 全部なくなっている。 var b = [2,5,1,3,4] b.sort // [1,2,3,4,5] 配列の中身自体をかえる。 順番がほんまの順番に変わる。 b.sorted // 配列の中身自体はを変更はしないけど 変更したものを一時的に配列にして返す var c = b.sorted print(b) // [2,5,1,3,4] sortしてないとする。配列の中身自体は変わらない print(c) // [1,2,3,4,5] 変更した物を一時的に返す順番がほんまの順番に変わる。 print(b.randomElement()!) // ランダムに返される 5とか b.shuffle() // [4,1,5,2,3] //シャッフルされる 配列の中身自体変わる。 b.shuffled() //配列の中身に変更はない 一時的に変数にいれシャッフルした配列を返す。 b.reverse() //[4,3,1,5,2] 順番逆 b.revesed() //ReversedCollection<Array<String>> ... よくわからん... revesed()はよくわからんので分かり次第更新します。 ■シーケンス操作 ■fllter 指定した条件の要素等を取り出して返す。 1から100の整数が入っている配列があるとして、偶数だけを取り出したい! let a = [Int](1...100) let b = a.filter { $0 % 2 == 0} print(b) //結果: [2,4,6,8,10,なになになになに長いので省略]1から100までの整数の偶数が取り出される。 クロージャを使用してる。 $0は配列の1から100までの数字全部の引数 まあ配列の中身全部って意味 あとはそれをif文のように条件を書きそれが返される。 ■map 配列中身ひとつずつ全部に指定した処理を行う。 let a = [10,20,30,40] let b = a.map{$0 * 2} //全部2倍にしたろ print(b) //結果: [20,40,60,80] ■forEach 配列の要素に順番に適応していく。 for-inと基本的には同じ ,forEachはbreakなどが使えない。 let a = [1,2,3] a.forEach { print($0) //結果: //1 //2 //3 順番に入る。 } とりあえずここまでとします。 都度必要になれば更新します。 参考にした記事というかこちらの方の記事のアウトプットです! 完璧版は下記リンクから飛べます! https://qiita.com/REON/items/1f33886d90b4f758e715
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

トレイリングクロージャ

トレイリングクロージャーとは、関数の引数の最後がクロージャの時、クロージャを()の外に書くことができる記法です。 func sample(parameter: Int, handler: (String) -> Void ) { handler("parameter is \(parameter)") } // トレイリングクロージャなし sample(parameter: 1, handler: { string in print(string) }) // トレイリングクロージャあり sample(parameter: 1) { string in print(string) } トレイリングクロージャ記法を使用した方がコードがスッキリして可読性が上がります。 Xcodeで関数をかくとき、クロージャ部分をダブルクリックもしくはエンターすると自動的にトレイリングクロージャ記法にしてくれます。 また、引数が1つの時でもトレイリングクロージャは使用できます。その場合は関数呼び出しの()も省略できます。 func sample(handler: (String) -> Void ) { handler("sample") } sample { string in print(string) } 参考 [増補改訂第3版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESS plusシリーズ) 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クロージャの属性

クロージャを関数や別のクロージャの引数として利用する場合にのみ有効な仕様として、属性とトレイリングクローリングがあります。 属性はクロージャの型の前に@属性名を追加して指定します。 func 関数名(引数名: @属性名 クロージャの型名) { 関数呼び出し時に実行される文 } escaping属性 escaping属性は、関数に引数として渡されたクロージャが、関数のスコープ外で保持される可能性があることを示します。 コンパイラはescaping属性の有無によって、クロージャがキャプチャを行う必要があるかを判別します。 var queue = [() -> Void]() func enqueue(operation: @escaping () -> Void) { queue.append(operation) } enqueue { print("executed") } enqueue { print("executed") } queue.forEach{ $0() } 上のプログラムでは、引数のクロージャは、関数のスコープ外で、保持されます。 なので、escaping属性を指定していないとエラーになります。 autoclosure属性 引数をクロージャで包むことで、遅延評価を実現するための属性です。 func or(_ lhs: Bool, _ rhs: @autoclosure () -> Bool) -> Bool { if lhs { print("true") return true } else { let rhs = rhs() print(rhs) return rhs } } func lhs() -> Bool { print("lhs関数が実行されました") return true } func rhs() -> Bool { print("rhs関数が実行されました") return false } or(lhs(), rhs()) 参考 [増補改訂第3版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESS plusシリーズ) 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プロパティオブザーバ

プロパティオブザーバとは ストアドプロパティの値の変更を監視し、変更前と変更後に文を実行するものです。 基本構文 var プロパティ名 = 初期値 { willSet { プロパティの変更前に実行する文 変更後の値には定数newValueとしてアクセスできる } didSet { プロパティの変更後に実行する文 } } サンプルコード struct Greeting { var to = "Yoshida" { willSet { print("willSet: (to: \(self.to), newValue: \(newValue))") } didSet { print("didSet: (to: \(self.to))") } } } var greeting = Greeting() greeting.to = "Yamada" // 出力 willSet: (to: Yoshida, newValue: Yamada) didSet: (to: Yamada)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

レイジーストアドプロパティ

レイジーストアドプロパティとは アクセスされるまで初期化を遅延させるプロパティです。 基本構文 lazy var インスタンスプロパティ名: プロパティの型 = 式 static lazy var スタティックプロパティ名: プロパティの型 = 式 サンプルコード struct SomeStruct { var value: Int = { print("valueの値を生成します") return 1 }() lazy var lazyValue: Int = { print("lazyValueの値を生成します") return 2 }() } var someStruct = SomeStruct() print("インスタンスを作成") print("valueのアクセス", someStruct.value) print("lazyValueのアクセス", someStruct.lazyValue) // 出力 valueの値を生成します インスタンスを作成 valueのアクセス 1 lazyValueの値を生成します lazyValueのアクセス 2 メリット 上の結果より、レイジーストアドプロパティはアクセスしたときに初期化されることがわかりました。 レイジーストアドプロパティを利用することで、初期化コストの高いプロパティの初期化をアクセスまで引き伸ばし、アプリのコスパを向上させることができます。 通常、ストアドプロパティの初期化時に、他のプロパティやメソッドを利用することはできません。 しかし、レイジーストアドプロパティはインスタンス生成より後に行われるため、初期化時に他のプロパティやインスタンスにアクセスすることができます。 struct SomeStruct { var value = 1 lazy var lazyValue = double(of: value) func double(of value: Int) -> Int { return value * 2 } } 参考 [増補改訂第3版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESS plusシリーズ) 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift]正しいエラー処理を選ぶ

※この記事はSwift by Sundellの内容を日本語に翻訳したものです。 概要 Swiftの主な特徴の一つは、コンパイル時の安全性です。 これにより、開発者はより予測可能でタイムエラーが発生しにくいコードを書くことができます。 しかし、様々な要因によってエラーが発生することがあります。今回は、そのようなエラーを適切に処理する方法とそのために使用できるツールについて見ていきます。 「Handling non-optional optionals in Swift」という記事では、実際にはオプショナルではないオプショナル型の処理方法を紹介しています。この記事では、強制アンラップの代わりにguardと組み合わせてpreconditionFailure()を使用すること、その為の便利なAPIを提供するマイクロフレームワーク「Require」を紹介しました。 その投稿以来、多くの人がpreconditionFailure()とassert()の違いと、それがSwiftのthrowing機能とどのように関連するのかについて尋ねてきました。なので、この記事ではこれらの言語の特徴とそれぞれの使い時を詳しく見ていきます。 エラー処理方法一覧 Swiftでエラーを処理する方法は次のとおりです。 nilを返す、またはエラー列挙型 エラー処理の最も簡単な形式は、エラーが発生した関数から単純にnil(または戻り値の型として列挙型Resultを使用している場合は.error型)を返すことです。これは多くの状況で非常に役立ちますが、すべてのエラー処理に使いすぎると、APIの使用がややこしくなり、欠陥のあるロジックが隠れてしまうリスクがあります。 throw MyErrorを使用してエラーを投げる これには、呼び出し元がdo, try, catchパターンを使用して潜在的なエラーを処理する必要があります。または、呼び出し地点でtry?を使用してエラーを無視することもできます。 assert()およびassertionFailure()の使用 特定の条件が真であることを確認します。デフォルトでは、これはデバッグビルドでfatal errorを引き起こしますが、リリースビルドでは無視されます。したがって、assertが引き起こされた場合に実行が停止することは保証されていないため、重大なランタイム警告のようなものです。 precondition()とpreconditionFailure()の使用 asserrtとの主な違いは、リリースビルドであっても、これらは常に評価されることです(Ounchecked最適化モードを使用してコンパイルしている場合を除く)。つまり、条件が満たされない場合、実行が続行されないことが保証されます。 fatalError()の呼び出し これは、Xcodeで生成されたinit(coder :)の実装でUIViewControllerなどのNSCoding準拠のシステムクラスをサブクラス化するときに、おそらく見たことがあるでしょう。これを呼び出すと、プロセスが直接強制終了されます。 exit()の呼び出し コードを使用してプロセスに存在するexit()を呼び出します。これは、コマンドラインツールやスクリプトで、グローバルスコープ(main.swiftなど)を終了する場合に非常に便利です。 エラーが回復可能か不可能か エラー処理の方法を選択する際に考慮すべき重要なことは、発生したエラーが回復可能かどうかを判断することです。 たとえば、サーバーを呼び出していて、エラーレスポンスを受け取ったとします。それは、私たちがどれほど素晴らしいプログラマーであり、サーバーインフラがどれほど堅固であっても必ず起こることです。したがって、これらのタイプのエラーを致命的で回復不可能なものとして扱うことは、たいてい間違いです。代わりに、私たちが望んでいるのは回復して、おそらく何らかの形のエラー画面をユーザーに表示することです。 では、この場合にエラー処理の適切な方法を選択するにはどうすればよいでしょうか。上記のリストを見ると次のように、回復可能な手法と回復不可能な手法に分類できます。 回復可能 nilを返す、またはエラー列挙型 throw MyErrorを使用してエラーを投げる 回復不能 assert()およびassertionFailure()の使用 precondition()とpreconditionFailure()の使用 fatalError()の呼び出し exit()の呼び出し この場合、非同期タスクを扱っているので、次のように、戻り値nilまたはエラー列挙型がおそらく最良の選択です。 class DataLoader { enum Result { case success(Data) case failure(Error?) } func loadData(from url: URL, completionHandler: @escaping (Result) -> Void) { let task = urlSession.dataTask(with: url) { data, _, error in guard let data = data else { completionHandler(.failure(error)) return } completionHandler(.success(data)) } task.resume() } } 同期APIの場合、throwは最適な選択です。これは、APIユーザーに適切な方法でエラーを処理するように「強制」するためです。 class StringFormatter { enum Error: Swift.Error { case emptyString } func format(_ string: String) throws -> String { guard !string.isEmpty else { throw Error.emptyString } return string.replacingOccurences(of: "\n", with: " ") } } ただし、エラーを回復できない場合があります。たとえば、アプリの起動時に構成ファイルをロードする必要があるとします。その構成ファイルが欠落していると、アプリが未定義の状態になります。 したがってこの場合、プログラムの実行を続行するよりもクラッシュする方が適切です。そのためには、より強力で回復不可能なエラー処理を使用する方が適切です。 この場合、構成ファイルが欠落している場合に実行を停止するためにpreconditionFailure()を使用します。 guard let config = FileLoader().loadFile(named: "Config.json") else { preconditionFailure("Failed to load config file") } プログラマーエラーと実行エラー 重要なもう1つの違いは、エラーの原因がロジックの誤りもしくは構成の誤りなのか、またはエラーがアプリケーションのフローの正当な部分と見なされるべきかどうかです。基本的に、プログラマーがエラーを引き起こしたかどうか、または外部要因が原因であったかどうかです。 プログラマーのエラーから保護する場合、ほとんどの場合、回復不可能な手法を使用する必要があります。そうすれば、アプリ全体で異常な状況をコード化する必要がなくなり、優れた一連のテストにより、これらのタイプのエラーができるだけ早く検出されることが確認されます。 たとえば、使用する前にビューモデルをバインドする必要があるビューを構築しているとします。ビューモデルはコードではオプショナル型になりますが、使用するたびにラップを解除する必要はありません。ただし、ビューモデルが何らかの理由で失われた場合でも、本番環境でアプリケーションをクラッシュさせる必要はありません。デバッグでエラーが発生しても十分です。これは、アサートを使用する場合です。 class DetailView: UIView { struct ViewModel { var title: String var subtitle: String var action: String } var viewModel: ViewModel? override func didMoveToSuperview() { super.didMoveToSuperview() guard let viewModel = viewModel else { assertionFailure("No view model assigned to DetailView") return } titleLabel.text = viewModel.title subtitleLabel.text = viewModel.subtitle actionButton.setTitle(viewModel.action, for: .normal) } } assertionFailure()はリリースビルドでサイレントにエラーが発生するため、上記のgardステートメントにreturnする必要があることに注意してください。 終わりに この投稿が、Swiftで利用可能なさまざまなタイプのエラー処理手法の違いを明らかにするのに役立つことを願っています。私のアドバイスは、1つのテクニックに固執するだけでなく、状況に応じて最も適切なテクニックを選択することです。一般に、エラーを致命的なものとして扱う必要がない限り、ユーザーエクスペリエンスを妨げないように、可能な限りエラーからの回復を常に試みることをお勧めします。 また、print(error)はエラー処理ではないことを忘れないでください? 元の記事 Picking the right way of failing in Swift Swift by Sundell
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】HTTP、URLSessionの初歩

千葉 大志. 「iOSアプリ開発デザインパターン入門」をサンプルコードの参考として,HTTPメソッド,URLSession周りの初歩的な知識や理解を簡単にまとめています。 課題 let urlString = "https://api.openweathermap.org/data/2.5/weather?units=\(unit)&APPID=\(appId)&q=\(city)" let url = URL(string:urlString)! var request = URLRequest(url:url) request.httpMethod="GET" let task = URLSession.shared.dataTask(with:request){(data,response,error)in        //内容に関しては省略        } URLとは 定義 struct URL { //イニシャライズ パラメータに文字列をとる init?(string: String) } let url = URL(string:String)! URL型としてインスタンスを生成する上でイニシャライズが必要となる。したがって、上記のようなURL(string:urlString)!と書くことでURL型のインスタンスが生成できる。 URLRequestとは 定義 struct URLRequest {  //イニシャライザー  init(    url: URL,    cachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy,    timeoutInterval: TimeInterval = 60.0  ) } var request = URLRequest(url:url) request.httpMethod = "GET" URLRequestは、ロードを行うために必要な2つのプロパティをカプセル化させるものであり、そのプロパティとはロードする対象となるURLとそのためのポリシーとされます。ここでいうポリシーはおそらく設定くらいの意味で、cachePolicyとtimeoutIntervalにあたります。上記イニシャライザーの記述の通り、 それぞれデフォルトで値が設定されているため、実際の使い方としてはポリシーを変更する必要がなければurlのみURL型で指定してあげればインスタンスが生成できます。 名称の通りURLがRequestを投げるために必要な条件と理解できます。 またドキュメントを読むと、URLRequestはHTTPやHTTPSの通信を目的としたHTTPメソッドやHTTPヘッダーを含むことがわかります。 In addition, for HTTP and HTTPS requests, URLRequest includes the HTTP method (GET, POST, and so on) and the HTTP headers. そのため、URLRequestのインスタンスは、上記のようにrequest.httpMethodといった形でHTTPメソッドを使うことができます。 HTTPメソッドとは 定義 var httpMethod: String? { get set } 端的にいえばサーバーに対するリクエストまたその種類がHTTPメソッドと言えます。GETやPOSTといった指定はSwift特有のものではなく、Web一般に広く共有されているものであることは理解しておかなくてはなりません。あくまでSwiftはメソッドを使う上で上記のコードを用いる必要があるというに過ぎず、押さえておくべきはGETやPOSTといったリクエストです。 HTTPメソッドはWebを通したリクエストに対するレスポンスで、後述のURLSessionはWebから返ってくるレスポンスに対する具体的な操作です。 URLSessionとは 定義 class URLSession : NSObject URLSessionクラスを使うことで、あれやこれやのデータのやり取りができます。 URLSessionには基本的なリクエストのために、シングルトンであるsharedが用意されています。あれこれの設定を必要とする場合にはshared以外を用いることになるので、URLSessionは都合sharedかshared以外かにわかれます。 ちなみにシングルトンとは、インスタンスが1個しか生成されないことを保証したい時に使われるものであり、それがそのままシングルトンの意味ともなります。特定のURLでのやりとりなのに、あちらこちらにインスタンス生じてやたらめったら通信したら収拾つかなくなるのは想像がつきます。ただし、URLSessionののsharedは定義上シングルトンとして理解されますが、厳密的にはシングルトンとは別のデフォルトインスタンスと呼んで差し支えないような性質のものです。 通信は非同期で行われ、完了時の処理は2種類に分かれます。delegateメソッドを呼ぶパターンとclosureが呼ばれるパターンです。 後者はdataTaskメソッドとして「iOSアプリ開発デザインパターン入門」にも登場しています。 dataTaskメソッドとは 定義 func dataTask(with url: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask パラメータにURL型のデータとescaping属性のクロージャをとります。そもそもdataTaskがURLの内容を復元し、その処理を行う操作だと考えれば、復元させる元の対象を指定しなければなりません。そのため、URL型のデータをパラメータにとります。また後者はリクエストに対するレスポンス、つまりデータをどのように処理するかという操作となります。操作するのはロードが完了した時点であり、escaping属性のクロージャで処理される形になります。 クロージャのそれぞれのパラメータは次のようになります。 data サーバーから返ってくるデータ response HTTPのヘッダーやステータスといったレスポンスのメタデータが渡される HTTP通信などの場合、通常HTTPURLresposeのオブジェクトとなる error リクエストの失敗もしくはリクエストが成功してもnilだった場合に示されるエラー クロージャにはエラーに対する処理を実装しておく必要があります 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift 構造体について

構造体について 構造体 構文 struct 構造体名 { var プロパティ名 = 初期値 func メソッド名() { 処理 } } 以下は例。 struct Item { var name = "メロン" var price = 400 func showName() { print("これは\(name)です") } } // インスタンスの作成 let item = Item() // メソッドの呼び出し item.showName() // 結果 これはメロンです // プロパティの参照 print(item.price) // 結果 400 変数にインスタンスを作成する事なくメソッドを呼び出す事も可能です。 Item().showName() // 結果 これはメロンです プロパティの値の書き換えは再代入で行う。 item.name = "スイカ" print(item.name) // 結果 スイカ プロパティ ストアドプロパティ 値を保持する為のプロパティ struct Item { var name = "メロン" // ストアドプロパティ // 略 } let item = Item() print(item.name) // 結果 メロン コンピューテッドプロパティ 値を計算する為のプロパティ。 以下のような注意点があります。 値が可変である為、変数(var)として定義する必要がある 型の指定が必須 struct Item { var price = 100 // 税込価格を計算するコンピューテッドプロパティ var priceWithTax:Int { let result = price * 1.1 return result } // 略 } let item = Item() print(item.priceWithTax) // 結果 110 内部では関数的な処理が行われているのですが、呼び出しの部分だけ見るとまるでストアドプロパティであるかのように参照することが出来ます。 ちなみに上のコンピューテッドプロパティは以下のようにシンプルに書くことが出来ます。 var priceWithTax:Int { price * 1.1 } これはSwiftの、ブロック内({ })の式が一つしかない場合、returnを省略することが出来るというルールを利用した書き方です。 中間変数resultに計算結果を代入する処理を省略し、ブロック内のコードを一行して、上記のルールに則ってreturnを省略したというわけです。 イニシャライズ インスタンス作成時に構造体の初期処理を行います。 struct Item { var name: String var price: Int init(name: String, price: Int) { self.name = name self.price = price } // 略 } let item = Item(name: "メロン", price: 400) print(item.name) //結果 メロン インスタンス作成時の引数は以下のようになっていますが、 let item = Item(ラベル名:引数, ラベル名:引数,) 注意する点は、このとき指定しているのでは引数名ではなくラベル名だということです。 先ほどのコードは呼び出しの際に引数名を指定しているように見えますが、 let item = Item(name: "メロン", price: 400) これはSwiftにラベルを省略すると引数名と同じ名前のラベルが自動で補完されるルールがあります。 先ほどのコードはinit()でラベルを省略しているのでこのルールが適応されているというわけです。 プロトコル 構文 protocol プロトコル名 { var ストアドプロパティ名: 型名 { get set } var コンピューテッドプロパティ名: 型名 { get } func メソッド名() } 構造体に実装しなければならないプロパティやメソッドの約束事を決める機能です。 あるプロトコルを適合させた構造体は、そのプロトコルに書かれているプロパティやメソッドを実装することが義務付けられます。 エナジードリンクを例に実際に書いてみます。 // プロトコルの定義 protocol energyDrinkProtocol { var amountOfArginine: Int { get set } // 保有するアルギニンの量を表すプロパティ func replenishEnergy() // エネルギーを補充するメソッド } 構造体に適合させてみます。 struct redbull: energyDrinkProtocol { var amountOfArginine = 125 var amountOfCaffeine = 40 func replenishEnergy() { print("元気百倍!!") } func stimulateTheBrain() { print("脳が活性化したよ!!") } } energyDrinkProtocolに従い、monster構造体はamountOfArginineプロパティとreplenishEnergy()メソッドを持っておりプロトコルの約束通りの実装です。なのでエラーは出ません。 これがもし、 struct redbull: energyDrinkProtocol { var amountOfCaffeine = 40 func stimulateTheBrain() { print("脳が活性化したよ!!") } } のようになっていると、プロトコルとの約束事に反する為エラーが出ます。 まとめると、プロトコルは構造体の仕様書のようなもので、構造体の実装内容をある程度保証する役割があります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む