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レスポンシブデザインをマスター

blog-page_footer_336




blog-page_footer_336




-iOS
-

執筆者:


comment

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

CAPTCHA


関連記事

【Swift】iOS15UIMenuの挙動変更について

1 はじめに2 UIMenuとは3 UIMenuの実装4 動作確認5 さいごに6 おすすめ書籍 はじめに こんにちは、suzukiです。ハーフモーダルの記事をみてiOS15についてあまりきにできていな ...

swift

[Swift]ObjectMapperで簡単にJSONを読み込む

1 はじめに2 準備3 実装3.1 基本的な使い方3.2 ネスト配列に対応してみよう4 さいごに はじめに こんにちは、onukiです。 私はSwiftでJSONを取り扱う際に、 ObjectMapp ...

【Swift】iOS14でブラウザが起動しない。

1 はじめに2 ブラウザの起動について3 原因について4 修正について5 おまけ:メールについて6 さいごに7 おすすめ書籍 はじめに こんにちはsuzukiです。iOS14がリリースされてしばらく経 ...

swift

[Swift3] ScrollViewを使ってみた!

1 はじめに2 縦スクロール3 横スクロール4 横スライドでページング5 さいごに6 おすすめ書籍 はじめに どーもはじめです。 ずっと苦手意識というかあまり使いたくないイメージを持っていたのですが、 ...

Apple製のフレームワークCombineを触ってみた

1 はじめに2 Combineとは3 Publishers3.1 Future4 Subscribers4.1 sink4.2 assign5 Operators5.1 Prepend5.2 Appe ...

フォロー

blog-page_side_responsive

2019年6月
 1
2345678
9101112131415
16171819202122
23242526272829
30  

アプリ情報

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