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

iOSでライブラリFSCalendarをつかって簡単にカレンダー表示

1 はじめに2 準備3 実装3.1 Storyboard3.2 コード3.3 タップの取得4 さいごに はじめに こんにちは、nukkkyです。 ツール系アプリ開発時にカレンダー表示を よく使うと思い ...

【Swift】XCUITestでScrollViewのテストをしてみる

1 はじめに2 XCUITestとは3 導入方法3.1 オブジェクトの配置3.2 UISCrollView3.3 ラベルとボタン4 テストのための設定4.1 ラベル5 テストコード5.1 SetUp5 ...

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

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

[Swift]MapViewでクラスタ機能を利用する。

1 はじめに2 クラスタリングとは3 PINのクラスタリング機能を利用する3.1 マップの作成3.2 PINの作成3.3 Pinのカスタマイズ3.4 カスタムしたPinの利用3.5 CustomPin ...

swift

端末のモデル名やサイズを簡単に取得できるライブラリ「Device」

1 はじめに2 準備3 試してみる3.1 端末モデル名3.2 画面サイズ3.3 端末の種類4 さいごに はじめに こんにちは、nukkyです。 今回は端末のサイズやモデル名などを 簡単に取得できるライ ...

フォロー

follow us in feedly

page_side_300rect

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

アプリ情報

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