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

Swiftでシェア機能や外部アプリ起動の導線を簡単に実装できるライブラリ「SwiftShareBubbles」

1 はじめに2 準備3 実装3.1 表示3.2 用意されているパターン4 さいごに はじめに こんにちは、nukkyです。 今回はSNSでのシェア機能や外部アプリ起動の導線を追加したいときに 簡単に実 ...

swift

SwiftでS3への画像アップロード

1 はじめに2 AWS上での事前準備3 CocoaPodsでAWS SDKをインストールをする4 認証の設定をする5 UIImageを保存して、URLを取得する6 S3へアップロードする7 さいごに ...

UserNotificationsの使い方について

1 はじめに2 UserNotificationsフレームワーク3 基本実装3.1 デリゲートの設定3.2 ユーザー許可3.3 デバイストークン取得後3.4 バックグラウンドで通知受信3.5 フォアグ ...

【iOS14】新機能WidgetKitへの挑戦【実践編】

1 はじめに2 Today Extensionとの違い3 ターゲットの追加4 StaticConfiguration4.1 TimelineProvider4.1.1 getSnapshot4.1.2 ...

iOS13で発生するUICollectionviewのカクつきを解消する

iOS13でCollectionViewの動作が少し変わりました。 Cellの入れ替え時にデータの更新を行う際にはどのように作成すれば良いか、関係のあるデリゲートを含め説明させていただいております。 おまけとして、Xcode11.3対応を行った際に対応した内容を簡単にですが記述しております。Xcode11対応をされる方の参考になればと思います。

フォロー

blog-page_side_responsive

2019年6月
 1
2345678
9101112131415
16171819202122
23242526272829
30  

アプリ情報

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