- 投稿日:2019-07-09T23:47:26+09:00
「iOS アプリ開発デザインパターン入門」を読んでの備忘録
こちらの本を読んで分からなかった内容を調べた(これから調べる)際のメモ
1. @objc func ~~~ の @objc って何ぞや?
答え
@objc を付けるとObjective-C側から呼び出す事ができる詳細
1. Objective-Cではメソッドをコンパイルすると2つの隠し引数(selfとcmd)を持った関数が生成される
2. Swiftでは1つのを隠し引数(オブジェクト自身)を持った関数が生成される
3. 隠し引数の数の違いによって相互利用が出来なくなってしまう
4. @objc を付けることでコンパイル時に2つの隠し引数を持ったメソッドが生成できる補足
プロパティにも @objc をつけることができるみたい参考
[Swift] @objcの話 [Objective-C]2. @escaping って何ぞや?
答え
@escaping を付けるとクロージャをスコープ外で保持できるclass A { private let storedClosure: () -> () // escapingを付けないとエラーになる init(closure: @escaping () -> ()) { storedClosure = closure } }補足
1. @escaping したクロージャ内でフィールド変数を参照する場合にはselfを付ける
2. 循環参照に気を付けるclass A { private let storedClosure: () -> () // escapingを付けないとエラーになる init(closure: @escaping () -> ()) { storedClosure = closure } } class B { private var a: A? private var count = 0 func doSomething() { // (2) 循環参照を避けるためにselfを弱参照する a = A(closure: { [weak self] in // (1) フィールド変数のcountにアクセスするためにselfを付ける self?.count += 1 }) } } do { let b = B() b.doSomething() }参考
・Swiftの @escaping と weak/unowned の理解
・Swift 3 の @escaping とは何か3. fileprivate って何ぞや?
答え
同一ファイル内であればアクセスできる修飾子
(名前の通りそのままですね)private修飾子との違い
Hello.swiftclass A { private var hoge = "hoge" fileprivate var fuga = "fuga" } let a = A() print(a.hoge) // 'hoge' is inaccessible due to 'private' protection level print(a.fuga) // fuga最後に
初めての投稿で「@」が謎のリンクになっていたので、そちらの解決方法もメモしておきます
答え
@を<span>タグで囲う
@arusu0629→ @arusu0629
<span>@</span>arusu0629→ @arusu0629
- 投稿日:2019-07-09T23:02:59+09:00
Optionalを含んだクロージャ引数があるSwiftメソッドをObjective-Cから使おうとしたらエラーが出たので回避した
nilかそうでないかで処理を分けるために、クロージャの引数をOptionalにしたSwiftのメソッドがあったのですが、
Objective-Cから使用するために@objc属性を付加したら、エラーが出て使えませんでした。エラー内容
Method cannot be marked @objc because the type of the parameter 4 cannot be represented in Objective-C
?♂️エラーが出たメソッド定義
ViewController.swift@objc public func go(completion: (SomeType?) -> ())?♂️エラー回避のための代替策
引数と戻り値を囲み、クロージャ自体をOptionalにする
ViewController.swift@objc public func go(completion: ((SomeType) -> ())?)引数をOptionalにすることを諦める
ViewController.swift@objc public func go(completion: (SomeType) -> ())この時の選んだ回避策
実際に行った回避策としては、クロージャを2つに分けました。
ViewController.swift@objc public func go(success: (SomeType) -> (), failure: (SomeType) -> ())あまり、遭遇機会もないかと思いますが、備忘録として書き残しておきます。
- 投稿日:2019-07-09T22:17:28+09:00
[Swift 5]TabBarのボタン(TabBarItem)をタップで画面をModal表示する簡単な方法
TabBarControllerで実装したボトムタブを選択すると、通常は画面が切り替わります。
今回は、特殊なボタンとして画面をModal(下から上へ出現)表示させたい時の実装です。(真ん中のボタンが丸く縁取られているアプリに多いと思います)
Modalで開きたい画面クラスが
TargetViewControllerと仮定して解説していきます。ソースコード
TabBarController.swiftimport UIKit final class TabBarController: UITabBarController { override func viewDidLoad() { super.viewDidLoad() delegate = self // UITabBarControllerDelegate } } // MARK: - UITabBarControllerDelegateに適合 extension TabBarController: UITabBarControllerDelegate { // TabBarItemが選択された時に呼ばれる func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool { // TabBarItemタップでModal表示をする画面を指定して実装 if viewController is TargetViewController { if let newVC = UIStoryboard(name: "Target", bundle: nil).instantiateInitialViewController() { tabBarController.present(newVC, animated: true, completion: nil) return false } } return true } }実装手順
delegate = selfを書くのを忘れないextentionでUITabBarControllerDelegateに適合するtabBarController(_:shouldSelect:)->Boolメソッドを実装- 開かれるViewControllerが対象のものだったら、という条件でif分岐
- あとは、ViewControllerをインスタンス化し、
present(_:animated:completion)メソッドで画面をModal表示させればOKです!NavigationControllerを使用している場合
TargetViewControllerでNavigationItemを使いたい等の理由でNavigationControllerを使用する場合
TabBarController.swiftif viewController.children.first is TargetViewController {というようにすればNavigationControllerが間にあっても判定可能です。
もし、もっと簡単な方法があればぜひ教えてください。
- 投稿日:2019-07-09T19:51:44+09:00
[Swift][iOS]TableViewのセル再利用の罠
はじめに
iOSアプリでGUIを作る際にはTableviewを使うことが非常に多いと思います。
このTableview、デフォルトだとセルのクラスはUITableViewCellで、表示出来るUIが事前に定められています(テキスト、サブテキスト等)。
たとえば画像を表示したかったり、ボタンを表示したかったり、実装したいUIによってはデフォルトのクラスを継承したカスタムクラスを作ってやる必要があります。
そんな際にバグってしまったセルの取扱いについてまとめておきます。バグった実装
例によってカスタムクラスをつくって、内部にはUITextFieldを設置して、ユーザーの入力を受け付けるようにすると、以下のようなバグが発生しました。
①1行目のセルのTextfieldに文字列を入力すると
②下にスクロールすると7行目くらいのセルに文字列が入力されてしまっている
バグの内容
実装したUIはセルの数が一定ではなく、ユーザーの入力によりセルが増減するものになります(初期状態はセルはひとつ)。セルを増やした際、1番目のセルに文字列を入力すると、それが「画面外の7番目くらいの別のセルにも反映されてしまう」バグに遭遇しました。
原因
ぐぐったら以下のQiitaの記事に辿りつきました。
UITableViewのあるセルに設定した値が、他のセルにも反映されてしまう
https://qiita.com/shikatani/items/88dff6ecf9684027862e要は画面外にあるセルは内部的には描写されておらず、必要に応じて描写されるようになっているようです。
画面外から画面内に入ってくるセルは、画面内から画面外に出ていくセルを再利用しているのです。対策
セルに登載されるデータはcellForRowAtで指定する訳ですが、事前にデータが固定されていないと実装が複雑になる感があります。今回の件は動的に登載されるべきデータが変更されることから、単純な実装ではうまくいかなかった訳です。上記のQiita記事では、バグは発生しているものの登載されるべきデータは静的に事前に指定されているので、セルを初期化すれば解決しています(∵画像の読み込み先URLは事前に決定されているから)。しかしながら本件のようなユーザーの入力にデータが依存するケースだと、入力されるデータを逐次保存しておかないと対応出来ないと思います。すなわち、予めセルに登載するデータ(=配列)を指定しておき、その配列の中身が更新される、という実装が必要になるかと。
終わりに
具体的な解決策は提示出来てませんが、Tableviewのセルに登載するデータは事前に指定してあげないと予期せぬ動作をするという事と、ググれば何でも出てくるという事を伝えたかった。

