質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
Firebase

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

Swift

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

SNS

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

864閲覧

[Swift] カスタムクラスから未読数をカウントする方法

ishiishiyay

総合スコア33

Firebase

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

Swift

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

SNS

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2019/07/15 03:23

編集2019/07/27 13:13

LINEのようなアプリを作っています。
トーク一覧画面にて、まだ開いていないメッセージの数を表示したいのですが、未読数の取得方法が分からず困っています...。お力添え頂けますと幸いです。

以下が作りたい画面のイメージです。名前、プロフ画像、送信時間などの表示はすでに出来ています。
イメージ説明

Table Viewに各種情報を表示させるためのカスタムクラスは以下のような構図になっています。
イメージ説明

Swift

1class New { 2 private var _sender_id = ""; 3 private var _sender_name = ""; 4 private var _url = ""; 5 private var _timeStamp: NSNumber = 1 6 private var _toID = ""; 7 private var _childkey = ""; 8 private var _listened = false 9 private var _toName = ""; 10 11 init(sender_id: String, sender_name: String, url: String, toID: String, timeStamp: NSNumber , childkey: String, listened: Bool, toName: String) { 12 _sender_id = sender_id; 13 _url = url; 14 _toID = toID 15 _timeStamp = timeStamp 16 _childkey = childkey 17 _listened = listened 18 _sender_name = sender_name 19 _toName = toName 20 } 21 22 var sender_id: String? { 23 return _sender_id; 24 } 25 26 var sender_name: String? { 27 return _sender_name; 28 } 29 30 var toID: String? { 31 return _toID; 32 } 33 34 var toName: String? { 35 return _toName; 36 } 37 38 var url: String? { 39 return _url; 40 } 41 42 var timeStamp: NSNumber? { 43 return _timeStamp; 44 } 45 46 var childkey: String? { 47 return _childkey; 48 } 49 50 var listened: Bool? { 51 return _listened; 52 } 53}

未読数表示は難易度が高そうだったので、cell.label.text = user.sender_name.countなどと書いてみてまずは合計メッセージ数の表示にトライしましたが、適切な数字を取得できませんでした。

三つのハードルがあるのではないかと考えています
⑴各友達とやり取りしたメッセージの合計数の取得(⬅︎実際にはこの数値は使いませんが。)
⑵各友達とのメッセージのやり取りうち、未読数の取得(自分が送信したメールで、相手がまだ開けていないものを含む)
⑶各友達が自分に送ったメッセージのうち未読数の取得

⑵ができれば、⑶はif文などを駆使すればできる気もするので、ひとまず⑵をクリアしたいです。

Swift

1 2class NewTalkVC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate/*, FetchData*/ { 3 var news = [New]() 4 var newsDictionary = [String: New]() 5 var friendName: String = "" 6 var friendName2: String = "" 7 var toID: String = "" 8 var chatPartnerId: String = "" 9 var chatPartnerId2: String = "" 10 var chatPartnerName: String = "" 11 var messages = [Message]() 12 13 @IBOutlet weak var NewTalkCollectionView: UICollectionView! 14 override func viewDidLoad() { 15 super.viewDidLoad() 16 getNewTalk() 17 } 18 19 func getNewTalk() { 20 let uid = Auth.auth().currentUser?.uid 21 Database.database().reference().child("user-messages").child(uid!).observe(.childAdded, with: { (snapshot) in 22 let messageId = snapshot.key 23 DBProvider.Instance.mediaMessagesRef.child(messageId).observe(.value, with: { (snapshot) in 24 if let d = snapshot.value as? [String:AnyObject]{ 25 if let sender_id = d["sender_id"] as? String { 26 let sender_name = d["sender_name"] as? String 27 let timeStamp = d["timeStamp"] as? NSNumber 28 let toID = d["toID"] as? String 29 let toName = d["toName"] as? String 30 let listened = d["listened"] as? Bool 31 let childkey = d["childkey"] as? String 32 let url = d["url"] as? String 33 34 let newMessage = New(sender_id: sender_id, sender_name: sender_name!, url:url!, toID: toID!, timeStamp: timeStamp!, childkey: childkey!, listened: listened!, toName: toName!) 35 36 if sender_id == Auth.auth().currentUser?.uid { 37 self.chatPartnerId = toID! 38 self.newsDictionary[self.chatPartnerId] = newMessage self.news = Array(self.newsDictionary.values) 39 self.news.sort(by: {Double($0.timeStamp!) < Double($1.timeStamp!)}) 40 } 41 //送る主が自分以外で、かつ、送り先が自分であるとき 42 else if toID == Auth.auth().currentUser?.uid { 43 self.chatPartnerId = sender_id 44 self.newsDictionary[self.chatPartnerId] = newMessage 45 self.news = Array(self.newsDictionary.values) 46 self.news.sort(by: {Double($0.timeStamp!) < Double($1.timeStamp!)}) 47 } 48 } 49 } 50 }, withCancel: nil) 51 52 }, withCancel: nil) 53 } //getNewTalk()終わり 54 55 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 56 return news.count 57 } 58 59 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 60 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "NewTalkCollectionViewCell", for: indexPath) as! NewTalkCollectionViewCell 61 let user = news[indexPath.row] 62 63 if user.sender_id == Auth.auth().currentUser?.uid { 64 self.chatPartnerId2 = user.toID! 65 } else { 66 self.chatPartnerId2 = user.sender_id! 67 } 68 69 70 if user.sender_id == Auth.auth().currentUser?.uid { 71 cell.label.text = user.toName 72 } 73 74 else if user.toID == Auth.auth().currentUser?.uid { 75 cell.label.text = user.sender_name 76 } 77 78 //以下試したこと 79 // var test1: Int = user.filter {$0.listened == false}.count 80 // var test2: Int = user.sender_name?.count 81 // cell.numberOfMessages.text = "(test1!)" 82 83 return cell 84 } 85 86}//class 87

なお、以前似たような質問をしたことがあり、当時は回答にもあるFilterを駆使すれば可能と思いましたが、
この方法だと、全友達とのやり取りの未読数の合計値しか取得できないため、やりたいことが実現できず...
https://teratail.com/questions/149399
(こちらはカスタムクラスに友達別に情報を分けずに、全友達との全メッセージを入れています。)
イメージ説明

20190727以下追記

各メッセージはListened変数を有します。
イメージ説明
Collection View内で該当のセルをタップしたら、Firebase上の変数が未読から既読に変わるようにしています。

Swift

1 func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 2 3 4 let newValuesForProfile = ["listened": true] 5 6//タップしたセルが自分に送られたメールであれば、既読に変更 7 if messages[indexPath.row].senderId == self.toID { 8 DBProvider.Instance.dbRef.child("Media_Messages").child(messages[indexPath.row].childkey!).updateChildValues(newValuesForProfile) 9 }

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

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

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

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

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

guest

回答1

0

ベストアンサー

まずはDBの構造がわからないと何とも言えないかと思います。
各ユーザ同士のメッセージを見たかどうかをどこに保存しているか、適切なタイミングで更新しているのか。
1対1のメッセージのやり取りだけを考えた場合には各メッセージに未読判定をつけておいてその件数を数えるような構造にすれば良いかなと思います。

変数名を見たところだと_listenedが未読、既読を管理しているものでしょうか?
だとすればそれを各ユーザごとにカウントしたら良いような気もしますが。
(構造を自分で考えたのであればわかりそうな気もするのでそう言う問題ではない?)

===2019/07/28 追記===
現在の作りでいくと一覧表示をさせるためにself.newsには送信ユーザごとの最新メッセージしか入っていないと思うのでfilterではカウントできないと思われます。
全メッセージが入っている配列に対してであれば、filterで複数条件を指定すれば良いので以下のようにすれば未読カウントがとれるかと思います。

var allMessages = [New]() // その人の全メッセージが入っている配列と仮定する // 未読かつ送信IDが同じ(その人の全メッセージではなくて、本当に全メッセージが入ってしまうのであればtoIDが自分宛の条件を追加) var test1: Int = allMessages.filter {$0.listened == false && $0.sender_id == user.sender_id}.count

または表示データを作成するgetNewTalk内で未読カウントなども考えられるかと思います。
Newクラスはメッセージ内容を保持するクラスだと思うので、メッセージ一覧の内容を保持するような新たなクラスを作ってgetNewTalk内で値を入れていく方がもしかしたら良いかもしれません。
(現在表示させてる内容だけであれば、名前、最終時間、未読数があれば良い?)
とりあえず、IDごとに未読数を保持するようなものを作って書いた場合

var unreadCount = [String:New]() // 送る主が自分以外で、かつ、送り先が自分であるとき // ここの中で未読数をカウントしていく else if toID == Auth.auth().currentUser?.uid { self.chatPartnerId = toID! ~ 省略 // 未読がfalseのときにカウントしていく if !listened { if let count = unreadCount[self.chatPartnerId] { unreadCount[self.chatPartnerId] = count + 1 } else { unreadCount[self.chatPartnerId] = 1 } } } // 上記でunreadCountにIDごとの未読数がカウントされてると思うので正しいかをログなどで確認してみる ~ 省略 // 以下cellForItemAt内 let user = news[indexPath.row] var test1 = unreadCount[user.sender_id] // これで未読数が取れるはず

実装するための考え方はこんな感じかと思います。
そもそものデータの持ち方をどうするか、APIがあるのであればそちら側に寄せるなどの考え方もあるかと思います。
長くなってしまったところと分かりにくい部分などもあるかもしれませんので何かあればコメントをお願いいたします。

投稿2019/07/19 20:16

編集2019/07/27 23:18
razuma

総合スコア1313

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

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

ishiishiyay

2019/07/27 13:16

razumaさん ご回答いただきありがとうございます。 以下インラインにてコメントさせていただいたので、ご確認頂けますと幸いです。 >>まずはDBの構造がわからないと何とも言えないかと思います。 本文の下の方に構造を追記しました! >>変数名を見たところだと_listenedが未読、既読を管理しているものでしょうか? はい、ご認識のとおりです。 >>だとすればそれを各ユーザごとにカウントしたら良いような気もしますが。 はい、ユーザーごとにカウントしたいのですが、そのカウント方法が分からず...  お力添え頂けますと幸いです...!
ishiishiyay

2019/07/28 03:23

Razumaさん、 詳細にありがとうございます!試してみます!
ishiishiyay

2019/07/31 15:10

Razumaさん、 前者の方法で無事に未読数を反映できました!! 自分では到底思いつかない方法でした、本当にありがとうございます...
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問