🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

TableView

TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

SNS

SNS(ソーシャル・ネットワーキング・サービス)は、 人と人とのつながりを促進したり、サポートしたりすることが可能なコミュニティ型のWebサービスです。

Q&A

解決済

1回答

871閲覧

[Swift]Custom Classの配列重複バグ

ishiishiyay

総合スコア33

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

TableView

TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

SNS

SNS(ソーシャル・ネットワーキング・サービス)は、 人と人とのつながりを促進したり、サポートしたりすることが可能なコミュニティ型のWebサービスです。

0グッド

0クリップ

投稿2019/09/28 10:41

みなさま、下記、お力添え頂けますと幸いです... 1ヶ月立ち往生しています...

前提

LINEのようなメッセージングアプリを作っています。
Firebaseから該当メッセージを取得してカスタムクラスのmessages配列に入れています。

Swift

1class Message { 2 private var _senderId = ""; 3 private var _url = ""; 4 private var _timeStamp: NSNumber = 1 5 private var _toId = ""; 6 private var _childkey = ""; 7 private var _listened = false 8 //クラスを初期化 9 init(senderId: String, url: String, toId: String, timeStamp: NSNumber , childkey: String, listened: Bool) { 10 _senderId = senderId; 11 _url = url; 12 _toId = toId 13 _timeStamp = timeStamp 14 _childkey = childkey 15 _listened = listened 16 // 13classes and objects 14 initializers 17 } 18 var senderId: String? 19 return _senderId; 20 } 21 var url: String? { 22 return _url; 23 } 24 //中略 25}

Aくん、Bくんのの二人とのトークがあり、Aくんとのメッセージ数は18個、Bくんとのメッセージ数は10個です。

Aくん、BくんのそれぞれのトークルームのView ControllerのViewdidappearの中で、messages.countを出力すると、それぞれ18と10が出力され、画面上でも同数のセルが表示されています。

Swift

1 override func viewDidAppear(_ animated:Bool) { 2 print(self.messages.count) //Aくんのトークルームに入ったら18, Bくんのときは10 3} 4```### 問題点 5ここからが非常に困っている箇所です。 6別途、iPhone上部のセンサーを覆い隠すとトリガーされる処理を書いています。 7 8```Swift 9@objc func proximitySensorStateChanged(){ 10 print(self.messages.count) 11    //中略:音声メッセージを再生する処理が続く 12}

ここで、Aくんのトークルームに入った状態でiPhone上部のセンサーを手で隠し、proximitysensorを実際に発動させます。print(self.messages.count)は18と出力されます。ここまでは問題ありません。一度Aくんのトークを出て、Bくんのトークに入りなおします。この状態でproximitysensorを発動させると、print(messages.count)は、18と10が連続で出力されます。先ほどまで入っていた方のトークルームの情報がなぜか残っています。

順番としてまず18を出力してから10を出力されます。確かに音声メッセージを聞いてみても、先にAくんのメッセージが流れ初めて、途中ですぐかぶせる形でBくんの音声が流れ始めます。message配列の箱が二つ作成されるのかと思います。

print(messages.count)という全く同じ処理をしているにも関わらず、proximitysensorの箇所で書くと異なるアウトプットとなってしまうのが不可解です。

ここでは音声再生処理の詳述は避けますが、上記により、Bくんの音声メッセージが聞きたいのに、同時に関係のないAくんのメッセージも流れてしまうという支障が生じています。

参考

Firebaseからメッセージ情報を取得して配列を作る処理は下記の通りです。
各友達との個別トークのViewControllerの中で書いています。
一番下に、proximitysensorに繋げるselectorも記載しています。

Swift

1 var messages = [Message]() 2 3//override func viewDidLoad()の中 4 Database.database().reference().child("user-messages").child(uid!).observe(.childAdded, with: { (snapshot) in 5 let messageId = snapshot.key 6 DBProvider.Instance.mediaMessagesRef.child(messageId).observe(.value, with: { (snapshot) in 7 if let d = snapshot.value as? [String:AnyObject]{ 8 if let url = d["url"] as? String { 9 let senderId = d["sender_id"] as? String 10 let toId = d["toID"] as? String 11 let childkey = d["childkey"] as? String 12 let listened = d["listened"] as? Bool 13 let timeStamp = d["timeStamp"] as? NSNumber 14 let newContact = Message(senderId: senderId!, url: url, toId: toId!, timeStamp: timeStamp! , childkey: childkey!, listened: listened!); 15 //自分が送ったボイスかつ、送り先がContactsVCで選んだ友達のとき。 16 if senderId == (Auth.auth().currentUser?.uid)! && toId! == self.toID { 17 self.messages.append(newContact); 18 } 19 //友達が送ったボイスかつ、送り先が自分 20 else if senderId == self.toID && toId == Auth.auth().currentUser?.uid { 21 self.messages.append(newContact); 22 } else { 23 } 24 //自分からそれ以外に送ったボイスや、友達が自分以外に送ったボイスはスルーする。 25 self.messages.sort(by: {Double($0.timeStamp!) < Double($1.timeStamp!)}) 26 } 27 } 28 }, withCancel: nil) 29 }, withCancel: nil) 30 31 32NotificationCenter.default.addObserver(self, selector: #selector(ChatVC.proximitySensorStateChanged), name: UIDevice.proximityStateDidChangeNotification, object: nil) 33

以上となります。もし何かお気付きの点がございましたら、コメント頂けますと大変幸いです。お手数ですが、よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

もしかしたらですが、個別トークのViewControllerが解放されていない可能性があるかもです。
個別トークのViewControllerが閉じられる時にdeinitが呼ばれているか確認してみてください。
もし呼ばれていないようでしたらClosure内での強参照がその原因の可能性が高いです。
Closure内では弱参照させるために [weak self] をつけてみてください。
例えば以下のうようにしてみてください。

Swift

1 Database.database().reference().child("user-messages").child(uid!).observe(.childAdded, with: { [weak self] (snapshot) in 2 let messageId = snapshot.key 3 DBProvider.Instance.mediaMessagesRef.child(messageId).observe(.value, with: { [weak self] (snapshot) in

このようにするとClosure内での自身への参照は弱参照となるので例えば
self.messages.append(newContact);
このような部分では以下のようにすることで参照可能となります。
self?.messages.append(newContact);

見当違いな回答でしたらすいません。

投稿2019/09/28 11:27

k17a

総合スコア19

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ishiishiyay

2019/09/28 12:52

k17aさん ご回答いただきありがとうございます。 ViewControllerから戻る際にdeinitが呼ばれておらず、教えていただいた通りに修正しましたら上手くいきました!!! ViewDidAppear内に記載している方のprint(self.messages.count)は修正前から、配列の重複などせずにちゃんと出力されるのが理解できませんが、とりあえずやっと解決できて本当によかったです!! 本当にありがとうございます、やっと前に進めそうです!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問