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]AlertControllerでメモリリークが起きた!便利なMemory Graph

1 はじめに2 今回の問題2.1 deinitの調査2.2 原因の調査3 解決策4 Memory Graphについて5 さいごに6 おすすめ書籍 はじめに こんにちは、suzukiです。この記事の結論 ...

[Swift]ループできるページングビューをUIScrollViewで作ってみた

1 はじめに1.1 前提条件2 ページングビューとは3 実装3.1 Storyboardの準備3.2 コードの実装4 仕組み5 さいごに はじめに こんにちは、nukkyです。 スライドショーやウォー ...

[Swift4]StringのSwft4変更点と文字列操作

1 はじめに2 Swift4でのString変更点2.1 コレクション化2.2 文字列長の取得2.3 文字列を複数行で定義3 文字列操作3.1 英大文字、小文字変換3.2 ひらがな、カタカナ変換3.3 ...

【Swift】スクリーンショットの検知

1 はじめに2 スクショを検知する方法3 使い方4 さいごに5 おすすめ書籍 はじめに こんにちは、suzukiです。今回はユーザがスクリーンショットを取得した場合を検知にする方法についてです。 使わ ...

swift

Swiftで絵文字を判定する方法

1 はじめに2 実装2.1 絵文字の判定2.2 UITextFieldで絵文字の排除3 さいごに はじめに こんにちは、nukkyです。 今回はアプリでの文字入力の際に 入力された文字が絵文字かどうか ...

フォロー

blog-page_side_responsive

2019年6月
 1
2345678
9101112131415
16171819202122
23242526272829
30  

アプリ情報

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