Anonymous
Пользовательские изображения ячеек UITableView путаются
Сообщение
Anonymous » 22 сен 2024, 00:07
У меня возникла проблема с перепутыванием изображений из-за повторного использования ячеек. Я решил эту проблему (по крайней мере, мне казалось, что я решил), выполнив проверку внутри ячейки на личность пользователя, чтобы свойство идентификации соответствовало URL-адресу изображения, полученному с сервера. Однако даже при этом мои изображения по-прежнему путаются между ячейками. Это мой код в пользовательском классе ячеек:
Код: Выделить всё
import UIKit
class AllUsersListCell: UITableViewCell {
var preImageRequestIdentity: String = ""
var imgUrl: String? {
didSet {
loadImageFromUrl()
}
}
let imgIcon: UIImageView = {
let ic = UIImageView()
ic.contentMode = .scaleAspectFill
ic.layer.cornerRadius = 5.0
ic.clipsToBounds = true
ic.tintColor = .lightGray
ic.backgroundColor = APP_YELLOW_COLOR
return ic
}()
let lblCaption: UILabel = {
let ic = UILabel()
ic.font = .appFontWithSize(size: 22.0)
return ic
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = .clear
selectionStyle = .none
addSubview(imgIcon)
imgIcon.translatesAutoresizingMaskIntoConstraints = false
imgIcon.leftAnchor.constraint(equalTo: safeAreaLayoutGuide.leftAnchor, constant: 24.0).isActive = true
imgIcon.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
imgIcon.widthAnchor.constraint(equalToConstant: 34.0).isActive = true
imgIcon.heightAnchor.constraint(equalTo: imgIcon.widthAnchor).isActive = true
addSubview(lblCaption)
lblCaption.translatesAutoresizingMaskIntoConstraints = false
lblCaption.leftAnchor.constraint(equalTo: imgIcon.rightAnchor, constant: 16.0).isActive = true
lblCaption.centerYAnchor.constraint(equalTo: imgIcon.centerYAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func loadImageFromUrl() {
guard imgUrl != "" else {
return
}
guard let imageUrl = imgUrl, let url = URL(string: imageUrl) else {
print("Invalid URL string")
return
}
URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
print("Failed to load image: \(error.localizedDescription)")
return
}
guard let data = data, let image = UIImage(data: data) else {
print("Invalid image data")
return
}
DispatchQueue.main.async {
self.imgIcon.image = image
}
}.resume()
}
func callProfileImageApi(identity: String) {
self.preImageRequestIdentity = identity
self.imgUrl = ""
Api.sharedInstance.httpGet(url: getUserProfileImageUrl(forUser: identity)) { (response, error) in
guard let r = response else {
print("response fell through")
return
}
if r.value(forKey: "image_url") as! String == "" {
self.imgUrl = ""
} else {
let iu = r.value(forKey: "image_url") as! String
let fullImageUrlString = "\(getBaseUrl())\(iu)"
if self.preImageRequestIdentity == identity {
self.imgUrl = fullImageUrlString
} else {
self.imgUrl = ""
self.callProfileImageApi(identity: identity)
}
}
}
}
}
и это код на реальной странице, которая является делегатом табличного представления:
Код: Выделить всё
//
// AllUsersChatListVC.swift
//
//
//
import UIKit
import CloudKit
import TwilioConversationsClient
import SwiftUI
class AllUsersChatListVC: GosViewController {
// Tapped other user's identity
var otherUserIdentity: String!
var tableView: UITableView!
var pullRefresher:UIRefreshControl = UIRefreshControl()// Added for table view pull to referesh so that we don't have to kill and start again the app
var arrTwillioUsers = [User]()
var aLabel: UILabel!
var isInitiallyLoading = false
override func viewDidLoad() {
super.viewDidLoad()
let defaults = UserDefaults.standard
if isUserLoggedIn() {
if let identity = defaults.string(forKey: kUserIdentity) {
currentUserIdentity = identity
} else {
currentUserIdentity = "UNKNOWN"
}
}
self.pullRefresher.tintColor = .black
self.pullRefresher.shadowColorOverAll = .black
view.backgroundColor = .white
configureNavBar()
configureSpacingLabel()
configureUserTableView()
self.showLoading()
self.isInitiallyLoading = true
callGetAllUsersAPI()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.tintColor = APP_YELLOW_COLOR // DEV: see if this causes color issues on dragging the screen up/down on all chat page
navigationController?.hidesBarsOnSwipe = false
navigationController?.hidesBarsOnTap = false
navigationController?.hidesBarsWhenKeyboardAppears = false
navigationController?.hidesBarsWhenVerticallyCompact = false
navigationController?.navigationBar.barStyle = .default
navigationController?.navigationBar.isHidden = false
navigationItem.setHidesBackButton(true, animated: true)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}
// Label that serves so the color doesn't change on the nav bar when dragged down
func configureSpacingLabel() {
aLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
aLabel.center = CGPoint(x: 100, y: 10)
aLabel.textAlignment = .left
aLabel.text = "Spacing label"
view.addSubview(aLabel)
}
func configureUserTableView() {
tableView = UITableView()
tableView.delegate = self
tableView.dataSource = self
tableView.register(AllUsersListCell.self, forCellReuseIdentifier: reuseId)
tableView.contentInset = .init(top: 16.0, left: 0, bottom: 0, right: 0)
tableView.backgroundColor = .white
view.addSubview(tableView)
tableView.tableFooterView = UIView(frame: .zero)
tableView.layer.backgroundColor = UIColor.white.cgColor
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
// pull to refresh added on tableview
self.pullRefresher.addTarget(self, action: #selector(self.onSwipeRefresh), for: .valueChanged)
self.tableView.refreshControl = self.pullRefresher
self.pullRefresher.tintColor = .black
}
// swipe lister of pull to refresh
@objc func onSwipeRefresh() {
print("in inSwipeRefresh")
self.callGetAllUsersAPI()
}
func configureNavBar() {
let topLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
topLabel.textAlignment = .center
topLabel.text = currentUserIdentity
topLabel.font = UIFont(name: GOS_FONT_NAME, size: vcTitleSize)
navigationItem.titleView = topLabel
self.navigationController?.setStatusBar(backgroundColor: APP_YELLOW_COLOR)
}
func callGetAllUsersAPI() {
if offline {
let user : User = User()
user.identity = "fadil"
arrTwillioUsers.append(user)
let user2 : User = User()
user2.identity = "Memara"
arrTwillioUsers.append(user2)
self.tableView.reloadData()
self.pullRefresher.endRefreshing()
self.hideLoading()
} else {
Api.sharedInstance.httpGet(url: WS_URL(url: GetAllUsersAPI)) { [weak self] (response, error) in
self?.pullRefresher.endRefreshing()
if self?.isInitiallyLoading ?? true {
self?.hideLoading()
self?.isInitiallyLoading = false
}
if (error == nil) {
self?.manageUserResponse(dict: response)
} else {
self!.showAlert(title: "Error", message: error?.domain)
}
}
}
}
func manageUserResponse(dict : NSDictionary?) {
guard let arr = dict?.value(forKey: param_users) else { return }
let arrUsers = arr as! [Any]
arrTwillioUsers.removeAll()
if arrUsers.count > 0 {
for userDictionary in arrUsers {
let user : User = User.init(dictionary: userDictionary as! NSDictionary)!
arrTwillioUsers.append(user)
}
}
arrTwillioUsers = arrTwillioUsers.filter({$0.identity != currentUserIdentity})
arrTwillioUsers = arrTwillioUsers.sorted(by: { $0.identity ?? "" < $1.identity ?? ""})
self.tableView.reloadData()
}
func handleClick(otherUser: String) {
print("in handleClick")
self.otherUserIdentity = otherUser
if offline {
prepareAndPushChatPage(cur: self.currentUserIdentity, oth: self.otherUserIdentity)
} else {
self.showLoading()
if isTokenExpired() {
ConversationsManager.shared.refreshAccessToken() {
self.prepareAndPushChatPage(cur: self.currentUserIdentity, oth: self.otherUserIdentity)
}
} else {
prepareAndPushChatPage(cur: self.currentUserIdentity, oth: self.otherUserIdentity)
}
}
}
func prepareAndPushChatPage(cur: String, oth: String) {
ConversationsManager.shared.initializeConversationManager(token: getToken(), conversationDelegate: self) {
self.loadChatPage(cur: self.currentUserIdentity, oth: self.otherUserIdentity)
}
}
func loadChatPage(cur: String, oth: String) -> Void {
guard oth != "" && cur != "" else {
return
}
let cvc = ChatVC()
cvc.currentUserIdentity = cur
cvc.currentChatPartnerIdentity = oth
// Prevent reopening for same user
//openChatWithUser = ""
DispatchQueue.main.async {
self.navigationController?.pushViewController(cvc, animated: true)
self.hideLoading()
}
self.chatVC = cvc
}
}
// MARK: - TableView Delegate
extension AllUsersChatListVC: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrTwillioUsers.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.handleClick(otherUser: arrTwillioUsers[indexPath.row].identity!)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reuseId, for: indexPath) as! AllUsersListCell
let objUser = arrTwillioUsers[indexPath.row]
cell.lblCaption.text = objUser.identity // actual text for a user, for a row in the users chat list
cell.lblCaption.font = UIFont(name: GOS_FONT_NAME, size: 22)
cell.callProfileImageApi(identity: objUser.identity!)
tableView.rowHeight = 60
return cell
}
}
что я делаю не так?
Подробнее здесь:
https://stackoverflow.com/questions/790 ... ges-mix-up
1726952876
Anonymous
У меня возникла проблема с перепутыванием изображений из-за повторного использования ячеек. Я решил эту проблему (по крайней мере, мне казалось, что я решил), выполнив проверку внутри ячейки на личность пользователя, чтобы свойство идентификации соответствовало URL-адресу изображения, полученному с сервера. Однако даже при этом мои изображения по-прежнему путаются между ячейками. Это мой код в пользовательском классе ячеек: [code]import UIKit class AllUsersListCell: UITableViewCell { var preImageRequestIdentity: String = "" var imgUrl: String? { didSet { loadImageFromUrl() } } let imgIcon: UIImageView = { let ic = UIImageView() ic.contentMode = .scaleAspectFill ic.layer.cornerRadius = 5.0 ic.clipsToBounds = true ic.tintColor = .lightGray ic.backgroundColor = APP_YELLOW_COLOR return ic }() let lblCaption: UILabel = { let ic = UILabel() ic.font = .appFontWithSize(size: 22.0) return ic }() override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) backgroundColor = .clear selectionStyle = .none addSubview(imgIcon) imgIcon.translatesAutoresizingMaskIntoConstraints = false imgIcon.leftAnchor.constraint(equalTo: safeAreaLayoutGuide.leftAnchor, constant: 24.0).isActive = true imgIcon.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true imgIcon.widthAnchor.constraint(equalToConstant: 34.0).isActive = true imgIcon.heightAnchor.constraint(equalTo: imgIcon.widthAnchor).isActive = true addSubview(lblCaption) lblCaption.translatesAutoresizingMaskIntoConstraints = false lblCaption.leftAnchor.constraint(equalTo: imgIcon.rightAnchor, constant: 16.0).isActive = true lblCaption.centerYAnchor.constraint(equalTo: imgIcon.centerYAnchor).isActive = true } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func loadImageFromUrl() { guard imgUrl != "" else { return } guard let imageUrl = imgUrl, let url = URL(string: imageUrl) else { print("Invalid URL string") return } URLSession.shared.dataTask(with: url) { data, response, error in if let error = error { print("Failed to load image: \(error.localizedDescription)") return } guard let data = data, let image = UIImage(data: data) else { print("Invalid image data") return } DispatchQueue.main.async { self.imgIcon.image = image } }.resume() } func callProfileImageApi(identity: String) { self.preImageRequestIdentity = identity self.imgUrl = "" Api.sharedInstance.httpGet(url: getUserProfileImageUrl(forUser: identity)) { (response, error) in guard let r = response else { print("response fell through") return } if r.value(forKey: "image_url") as! String == "" { self.imgUrl = "" } else { let iu = r.value(forKey: "image_url") as! String let fullImageUrlString = "\(getBaseUrl())\(iu)" if self.preImageRequestIdentity == identity { self.imgUrl = fullImageUrlString } else { self.imgUrl = "" self.callProfileImageApi(identity: identity) } } } } } [/code] и это код на реальной странице, которая является делегатом табличного представления: [code]// // AllUsersChatListVC.swift // // // import UIKit import CloudKit import TwilioConversationsClient import SwiftUI class AllUsersChatListVC: GosViewController { // Tapped other user's identity var otherUserIdentity: String! var tableView: UITableView! var pullRefresher:UIRefreshControl = UIRefreshControl()// Added for table view pull to referesh so that we don't have to kill and start again the app var arrTwillioUsers = [User]() var aLabel: UILabel! var isInitiallyLoading = false override func viewDidLoad() { super.viewDidLoad() let defaults = UserDefaults.standard if isUserLoggedIn() { if let identity = defaults.string(forKey: kUserIdentity) { currentUserIdentity = identity } else { currentUserIdentity = "UNKNOWN" } } self.pullRefresher.tintColor = .black self.pullRefresher.shadowColorOverAll = .black view.backgroundColor = .white configureNavBar() configureSpacingLabel() configureUserTableView() self.showLoading() self.isInitiallyLoading = true callGetAllUsersAPI() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) navigationController?.navigationBar.tintColor = APP_YELLOW_COLOR // DEV: see if this causes color issues on dragging the screen up/down on all chat page navigationController?.hidesBarsOnSwipe = false navigationController?.hidesBarsOnTap = false navigationController?.hidesBarsWhenKeyboardAppears = false navigationController?.hidesBarsWhenVerticallyCompact = false navigationController?.navigationBar.barStyle = .default navigationController?.navigationBar.isHidden = false navigationItem.setHidesBackButton(true, animated: true) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) } // Label that serves so the color doesn't change on the nav bar when dragged down func configureSpacingLabel() { aLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21)) aLabel.center = CGPoint(x: 100, y: 10) aLabel.textAlignment = .left aLabel.text = "Spacing label" view.addSubview(aLabel) } func configureUserTableView() { tableView = UITableView() tableView.delegate = self tableView.dataSource = self tableView.register(AllUsersListCell.self, forCellReuseIdentifier: reuseId) tableView.contentInset = .init(top: 16.0, left: 0, bottom: 0, right: 0) tableView.backgroundColor = .white view.addSubview(tableView) tableView.tableFooterView = UIView(frame: .zero) tableView.layer.backgroundColor = UIColor.white.cgColor tableView.translatesAutoresizingMaskIntoConstraints = false tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true tableView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true tableView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true // pull to refresh added on tableview self.pullRefresher.addTarget(self, action: #selector(self.onSwipeRefresh), for: .valueChanged) self.tableView.refreshControl = self.pullRefresher self.pullRefresher.tintColor = .black } // swipe lister of pull to refresh @objc func onSwipeRefresh() { print("in inSwipeRefresh") self.callGetAllUsersAPI() } func configureNavBar() { let topLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21)) topLabel.textAlignment = .center topLabel.text = currentUserIdentity topLabel.font = UIFont(name: GOS_FONT_NAME, size: vcTitleSize) navigationItem.titleView = topLabel self.navigationController?.setStatusBar(backgroundColor: APP_YELLOW_COLOR) } func callGetAllUsersAPI() { if offline { let user : User = User() user.identity = "fadil" arrTwillioUsers.append(user) let user2 : User = User() user2.identity = "Memara" arrTwillioUsers.append(user2) self.tableView.reloadData() self.pullRefresher.endRefreshing() self.hideLoading() } else { Api.sharedInstance.httpGet(url: WS_URL(url: GetAllUsersAPI)) { [weak self] (response, error) in self?.pullRefresher.endRefreshing() if self?.isInitiallyLoading ?? true { self?.hideLoading() self?.isInitiallyLoading = false } if (error == nil) { self?.manageUserResponse(dict: response) } else { self!.showAlert(title: "Error", message: error?.domain) } } } } func manageUserResponse(dict : NSDictionary?) { guard let arr = dict?.value(forKey: param_users) else { return } let arrUsers = arr as! [Any] arrTwillioUsers.removeAll() if arrUsers.count > 0 { for userDictionary in arrUsers { let user : User = User.init(dictionary: userDictionary as! NSDictionary)! arrTwillioUsers.append(user) } } arrTwillioUsers = arrTwillioUsers.filter({$0.identity != currentUserIdentity}) arrTwillioUsers = arrTwillioUsers.sorted(by: { $0.identity ?? "" < $1.identity ?? ""}) self.tableView.reloadData() } func handleClick(otherUser: String) { print("in handleClick") self.otherUserIdentity = otherUser if offline { prepareAndPushChatPage(cur: self.currentUserIdentity, oth: self.otherUserIdentity) } else { self.showLoading() if isTokenExpired() { ConversationsManager.shared.refreshAccessToken() { self.prepareAndPushChatPage(cur: self.currentUserIdentity, oth: self.otherUserIdentity) } } else { prepareAndPushChatPage(cur: self.currentUserIdentity, oth: self.otherUserIdentity) } } } func prepareAndPushChatPage(cur: String, oth: String) { ConversationsManager.shared.initializeConversationManager(token: getToken(), conversationDelegate: self) { self.loadChatPage(cur: self.currentUserIdentity, oth: self.otherUserIdentity) } } func loadChatPage(cur: String, oth: String) -> Void { guard oth != "" && cur != "" else { return } let cvc = ChatVC() cvc.currentUserIdentity = cur cvc.currentChatPartnerIdentity = oth // Prevent reopening for same user //openChatWithUser = "" DispatchQueue.main.async { self.navigationController?.pushViewController(cvc, animated: true) self.hideLoading() } self.chatVC = cvc } } // MARK: - TableView Delegate extension AllUsersChatListVC: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return arrTwillioUsers.count } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { self.handleClick(otherUser: arrTwillioUsers[indexPath.row].identity!) } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: reuseId, for: indexPath) as! AllUsersListCell let objUser = arrTwillioUsers[indexPath.row] cell.lblCaption.text = objUser.identity // actual text for a user, for a row in the users chat list cell.lblCaption.font = UIFont(name: GOS_FONT_NAME, size: 22) cell.callProfileImageApi(identity: objUser.identity!) tableView.rowHeight = 60 return cell } } [/code] что я делаю не так? Подробнее здесь: [url]https://stackoverflow.com/questions/79010465/uitableview-custom-cell-images-mix-up[/url]