iOS

Swift [unowned self]を[weak self]に修正してみた

投稿日:2019年6月10日 更新日:

はじめに

こんにちはsuzukiです「SwiftUI」が発表されました。レイアウト作成がとてもしやすそうでした。かなり触りやすそうに思えたのですが、業務ではデザインの指示書で細かい指示が出る場合が多いのです。細かいレイアウトも記述した時のコード全体の見易さが気になるところです。

それでは本題です。
リリース済みのアプリが特定の画面でたまに落ちると言われコードを確認すると、通信後のクロージャーの中に[unowned self]と記述していました。
[unowned self]とは、非所有参照でselfをキャプチャする事です。
メモリリークを防ぐため、クロージャー内で新しい非所有参照のselfを使い循環参照を起こらなくします。
[unowned self]はキャプチャされたselfが削除されないことが前提です。
しかしながら通信中にナビゲーションの閉じるボタンが有効だったため、自画面が削除されてアプリが落ちてました。

通信環境の再現

通信環境が良い時はレスポンスがすぐ返却されるため自画面の削除前にクロージャが呼ばれるのですが、不安定な回線でレスポンスが遅れた時に自画面が閉じられクラッシュしていました。
iOSの設定アプリからデベロッパを選択し通信環境を変更して再現をしました。

その上で、通信中に自画面を閉じたら、見事にクラッシュしました。
普段の開発環境で通信環境が悪いときの挙動をテストするなどはこちらの機能がとても便利です。
是非使っていきましょう。

unowned self

[unowned self] 使うサンプルのプログラムを作成しました。
Notificationを利用して非同期の処理を通信から通知に置き換えております。実際はNSNotificationでは循環参照が起きないため[unowned self]は記述不要ですが、動作確認のため記述しています。

StoryBoard

  • NavigationControllerの追加
  • ViewControllerにButtonを追加
  • NextViewControllerを追加
  • NextViewControllerにLabelを追加
  • Buttonに遷移を追加

続いてコードです。[unowned self]を使用しているコードです。

画面表示時に下記を行っています。

  • 通知の受信設定”endAsyncMethod”の通知を受信したら、self.updateLabel()を行う
  • 2秒後に通知”endAsyncMethod”を行う

2秒以内にナビゲーションの戻るをタップするとアプリがクラッシュします。
Fatal error: Attempted to read an unowned reference but the object was already deallocated

修正方法

今回の場合アプリでは[unownde self]を[weak self]に置き換えました。
クロージャの記述を下記のように切り替えています。

[weak self]ですが、クロージャーに自分の参照を渡す際にキャプチャされるselfがオプショナルで渡せます。
オプショナルなので実際に破棄された場合のselfはnilになるので上記のコードのようにguard let self = self else{return}
でselfがnilの時にUIの更新を行わせないように記述をすることが可能です。

さいごに

[unowned self]そのものが悪いのではなく、途中で設計の周知ができなかった、引き継ぎで情報共有が不十分であった、等でバグを発生させてしまったように思えます。なぜなら他の箇所では[unowned self]を利用するため、途中で閉じれないように制御されていたためです。
今回はある程度レイヤーごとに役割が分割されていたのでViewControllerのunowned selfを躊躇なく[weak selfに]置き換えましたが、保存処理やフラグ管理が入り乱れてたら簡単には判断できませんでした。初期設計とドキュメントのいいところと悪いところ両方を感じたバグでした。

おすすめ書籍

詳解 Swift 第4版  リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)  よくわかるAuto Layout iOSレスポンシブデザインをマスター

page_footer_300rect




page_footer_300rect




-iOS
-

執筆者:


comment

メールアドレスが公開されることはありません。

CAPTCHA


関連記事

swift

Swift3 [XIBファイル] コードでの呼び出し方まとめ

1 はじめに1.1 前提条件2 TableViewCell2.1 XIBの準備2.2 ViewControllerでの呼び出し3 CollectionView3.1 XIBの準備3.2 ViewCon ...

[Swift]クラスタされているPINを取得する

1 はじめに2 前回からの修正箇所3 クラスタリングされたPINの内容を取得する3.1 クラスタリングされているPINか判別3.2 クラスタリングされているPINを取得する4 TableViewとの連 ...

swift

[Swift3] スクロールする画面に固定でボタンを表示する方法

1 はじめに1.1 前提条件2 Storyboardの準備3 Controllerの実装3.1 スクロールする画面の実装(TableView)3.2 固定で表示するボタンを配置している画面の実装(Co ...

swift

[Swift3] SwitchとEnumを使ってSectionやCellを指定する

1 はじめに1.1 環境2 Enumの用意3 Tableの用意4 Cellの返却にEnumを使用する5 さいごに はじめに どうも、はじめです。 今回はSectionやCellの指定にSwitchとE ...

swift

[Swift]動画広告を最後まで見たら何かするアレをAPPLOVINでやってみた

1 はじめに1.1 前提条件2 準備3 実装3.1 Xcodeの設定3.2 広告の再生4 テスト設定とかアプリ管理5 さいごに はじめに こんにちは、nukkyです。 今回はタイトルの通り、アプリでよ ...

フォロー

follow us in feedly

page_side_300rect

2019年6月
« 5月    
 1
2345678
9101112131415
16171819202122
23242526272829
30  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。