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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

Firebase

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

TableView

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

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

Q&A

解決済

1回答

1663閲覧

UICollectionViewのCellが更新にされない

yuka0128

総合スコア4

Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

Firebase

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

TableView

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

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

0グッド

0クリップ

投稿2021/08/10 04:57

編集2021/08/10 06:12

UICollectionViewについての質問です。

・解決したいこと
cellがうまくリアルタイムで更新されない

・実装したいこと
写真右上の✖︎ボタンをタップしたらそのcellを削除したい(リアルタイムで更新させたい)

・試したこと
buttonが押下されたときにcollectionView.loadData()やlayoutSubviews()を使用しましたがうまくいきません。
バックはしっかりと実装できていてViewだけが更新されません。
そのためControllerを再表示するとしっかりとそのcellは削除されます。

ソースコードを添付しますがprotocolを使っているので見にくいかもしれません。申し訳ありません。

controller側のソースコード

Swift

1import UIKit 2 3private let reuseIdentifier = "UserCell" 4private let headerIdentifier = "HeaderView" 5 6class BlockedListController: UICollectionViewController { 7 8 //MARK: - Properties 9 10 private var users = [User]() { 11 didSet { collectionView.reloadData() } 12 } 13 14 private var ifNoOneLabel: UILabel = { 15 let label = UILabel() 16 label.isHidden = true 17 label.text = "現在ブロック中のアカウントはいません????" 18 label.textAlignment = .center 19 label.textColor = .white 20 label.font = UIFont.boldSystemFont(ofSize: 14) 21 return label 22 }() 23 24 private var ifNoOneLabel2: UILabel = { 25 let label = UILabel() 26 label.isHidden = true 27 label.text = "ブロックしたアカウントはここに表示されます" 28 label.textAlignment = .center 29 label.textColor = .white 30 label.font = UIFont.systemFont(ofSize: 12) 31 return label 32 }() 33 34 //MARK: - Lifecycle 35 36 override func viewDidLoad() { 37 super.viewDidLoad() 38 configureUI() 39 blockedUsersAreExist() 40 fetchBlockedUsers() 41 } 42 43 override func viewDidLayoutSubviews() { 44 super.viewDidLayoutSubviews() 45 fetchBlockedUsers() 46 } 47 48 //MARK: - API 49 50 private func fetchBlockedUsers() { 51 UserService.fetchBlockedUsers { users in 52 self.users = users 53 } 54 } 55 56 private func blockedUsersAreExist() { 57 UserService.blockedUsersAreExist { bool in 58 self.ifNoOneLabel.isHidden = !bool 59 self.ifNoOneLabel2.isHidden = !bool 60 } 61 } 62 63 //MARK: - Helpers 64 65 private func configureUI() { 66 collectionView.backgroundColor = .backgroundColor 67 collectionView.register(BlockedListCell.self, forCellWithReuseIdentifier: reuseIdentifier) 68 collectionView.register(BlockedListHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerIdentifier) 69 70 let stack = UIStackView(arrangedSubviews: [ifNoOneLabel, ifNoOneLabel2]) 71 stack.axis = .vertical 72 stack.spacing = 4 73 74 collectionView.addSubview(stack) 75 stack.centerX(inView: collectionView) 76 stack.anchor(top: collectionView.topAnchor, paddingTop: 240) 77 } 78} 79 80//MARK: - UICollectionViewDataSource 81 82extension BlockedListController { 83 override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 84 return users.count 85 } 86 87 override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 88 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! BlockedListCell 89 cell.delegate = self 90 cell.viewModel = UserCellViewModel(user: users[indexPath.row]) 91 return cell 92 } 93} 94 95//MARK: - UICollectionViewDelegate 96 97extension BlockedListController { 98 override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { 99 let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath) as! BlockedListHeader 100 header.delegate = self 101 return header 102 } 103} 104 105//MARK: - UICollectionViewDelegateFlowLayout 106 107extension BlockedListController: UICollectionViewDelegateFlowLayout { 108 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 109 return 1 110 } 111 112 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { 113 return 1 114 } 115 116 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 117 let width = (view.frame.width - 2) / 3 118 return CGSize(width: width, height: width) 119 } 120 121 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { 122 return CGSize(width: view.frame.width, height: 60) 123 } 124} 125 126//MARK: - BlockedListHeaderDelegate 127 128extension BlockedListController: BlockedListHeaderDelegate { 129 func handleDismissal() { 130 navigationController?.popViewController(animated: true) 131 } 132} 133 134//MARK: - BlockedListCellDelegate 135 136extension BlockedListController: BlockedListCellDelegate { 137 func unblockUser(withUid uid: String) { 138 UserService.unblockUser(withUid: uid) { _ in 139 self.fetchBlockedUsers() 140 self.collectionView.reloadData() 141 } 142 } 143}

cell側のソースコード

Swift

1import UIKit 2import SDWebImage 3 4protocol BlockedListCellDelegate: AnyObject { 5 func unblockUser(withUid uid: String) 6} 7 8class BlockedListCell: UICollectionViewCell { 9 10 //MARK: - Properties 11 12 weak var delegate: BlockedListCellDelegate? 13 14 var viewModel: UserCellViewModel? { 15 didSet { populateUserData() } 16 } 17 18 private let profileImageView: UIImageView = { 19 let iv = UIImageView() 20 iv.contentMode = .scaleAspectFill 21 iv.backgroundColor = .lightGray 22 iv.clipsToBounds = true 23 return iv 24 }() 25 26 private let fullnameLabel: UILabel = { 27 let label = UILabel() 28 label.textColor = .white 29 label.font = UIFont.boldSystemFont(ofSize: 14) 30 return label 31 }() 32 33 private lazy var unblockButton: UIButton = { 34 let button = UIButton(type: .system) 35 button.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal) 36 button.setDimensions(height: 30, width: 30) 37 button.tintColor = .lightGray 38 button.addTarget(self, action: #selector(handleUnblock), for: .touchUpInside) 39 return button 40 }() 41 42 //MARK: - Lifecycle 43 44 override init(frame: CGRect) { 45 super.init(frame: frame) 46 configureUI() 47 } 48 49 required init?(coder: NSCoder) { 50 fatalError("init(coder:) has not been implemented") 51 } 52 53 //MARK: - Actions 54 55 @objc func handleUnblock() { 56 guard let uid = viewModel?.user.uid else { return } 57 delegate?.unblockUser(withUid: uid) 58 } 59 60 //MARK: - Helpers 61 62 private func configureUI() { 63 addSubview(profileImageView) 64 profileImageView.setDimensions(height: 80, width: 80) 65 profileImageView.layer.cornerRadius = 80 / 2 66 profileImageView.centerX(inView: self) 67 profileImageView.centerY(inView: self) 68 69 addSubview(fullnameLabel) 70 fullnameLabel.centerX(inView: profileImageView) 71 fullnameLabel.anchor(top: profileImageView.bottomAnchor, paddingTop: 8) 72 73 addSubview(unblockButton) 74 unblockButton.anchor(top: topAnchor, right: rightAnchor, paddingTop: 6, paddingRight: 6) 75 } 76 77 private func populateUserData() { 78 guard let viewModel = viewModel else { return } 79 fullnameLabel.text = viewModel.fullname 80 profileImageView.sd_setImage(with: viewModel.profileImageUrl, completed: nil) 81 } 82} 83 84

ビルドするとこんな感じです。
このイメージ右上の✖︎を押下したらそのcellを削除したい
イメージ説明

もう一度そのページを読み込んだと場合は成功
イメージ説明

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

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

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

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

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

hoshi-takanori

2021/08/10 05:50

ソースも貼らずに質問されても何も分かりません。
yuka0128

2021/08/10 06:12

大変失礼致しました。 追加しましたので宜しくお願い致します。
hoshi-takanori

2021/08/10 08:31

ソースありがとうございます。プロトコルをちゃんと使って、読みやすく整理して書いてあると感じました。 たぶん UserService で API を叩いて、結果をコールバックで受け取ってるんだと思いますが、unblockUser ではデータを更新する API を叩いて、その結果が返ってからコールバックを呼んでますか? (結果が返る前にコールバックを呼んで、その中で fetchBlockedUsers を実行してるために更新される前のデータが読み込まれてるのでは?) あと、余計なお世話とは思いますが、UserService の各操作にコールバックを渡すより、Observer パターンで blockedUsers に変更があったときに通知を受け取るようにした方が綺麗になると思います。
yuka0128

2021/08/11 11:00 編集

早々のご返答ありがとうございます。 コードレビューまでしてくださり大変嬉しく思います。 仰る通り、fetchBlockedUsersでユーザーが空の場合にコールバックが呼ばれていませんでした。なのでfetchしてくるusersがisEmptyか否かで分岐させたところ正常に作動しました。 いえいえ!むしろそのようなことを教えてくださりありがとうございます。 絶対Rxを入れた方がいいですよね。。
hoshi-takanori

2021/08/11 16:22

動いて良かったです。iOS 13 以降なら Rx の代わりに iOS 付属の Combine フレームワークを使っても良いと思いますが、ちょっと大袈裟すぎる気もしますね…。
yuka0128

2021/08/11 16:32

Combineですね!早速勉強してみたいと思います。 いえいえ、まだまだ実装できない自分の勉強不足を痛感しています。 改めましてこの度は本当にありがとうございました。 また何かありましたら宜しくお願い致します。
guest

回答1

0

自己解決

APIのコールバックがうまく呼び出されていないことが原因でした。
上記のhoshi-takanori様のご返答が大変参考になりました。

投稿2021/08/11 16:36

編集2021/08/11 16:37
yuka0128

総合スコア4

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問