当我迅速从该视图控制器移动时,为啥我的 Collectionview 单元格没有显示?

Posted

技术标签:

【中文标题】当我迅速从该视图控制器移动时,为啥我的 Collectionview 单元格没有显示?【英文标题】:Why my Collectionview cells are not showing when i move from that viewcontroller in swift?当我迅速从该视图控制器移动时,为什么我的 Collectionview 单元格没有显示? 【发布时间】:2021-04-04 07:08:46 【问题描述】:

我能够解析 JSON 并在 Collectionview 中添加单元格.. 但是如果我从这个 Viewcontroller 移动到 viewcontroller 则 collectionview 不会显示.. 但在 JSON 中添加数据

添加collectionview和JSON解析的代码:

class ImageItemModel
var title: String?
var profileImage: UIImage?
var pic_id: Double?

init(title: String?, imgTitle: UIImage?, pic_id: Double?) 
    self.title = title
    self.profileImage = imgTitle
    self.pic_id = pic_id


class EditProfileImageViewController: UIViewController 

@IBOutlet weak var titleTextfield: UITextField!
private var imageProfile : UIImage?
private var imagePicker : EasyImagePicker?


@IBOutlet weak var collectionView: UICollectionView!
var arrImageItems = [ImageItemModel]()

@IBAction func imgtitleSaveBtn(_ sender: Any) 
    postServiceCall()


fileprivate func postServiceCall()
    
   if titleTextfield.text?.trim() == ""
   return self.view.makeToast("please add service title")
   
    let parameters = ["image_title" : titleTextfield.text?.trim() ?? ""]
    
    APIReqeustManager.sharedInstance.uploadMultipartFormData(param: parameters, url: CommonUrl.edit_profile_images, image: imageProfile, fileName: "image", vc: self, isHeaderNeeded: true) (responseData) in
        print("edit profile result \(responseData)")
            if let result = responseData.dict?["result"] as? NSDictionary
                    let success = result["status"] as? [String : Any]
                    let message = success?["message"] as? String
                if message == "Success"
                    let image = result["image"] as? [String : Any]
                    let picId = image?["id"]
                    self.arrImageItems.append(ImageItemModel(title: self.titleTextfield.text, imgTitle: self.imageProfile, pic_id: picId as! Double))
                    self.collectionView.reloadData()
                
                else
                    self.view.makeToast(CommonMessages.somethingWentWrong)
                
            
        
    
 extension EditProfileImageViewController : UICollectionViewDelegate,UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
    return arrImageItems.count


func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as! ImageCollectionViewCell
    cell.imgView.image = arrImageItems[indexPath.item].profileImage
    cell.lblTitle.text = arrImageItems[indexPath.row].title
    cell.deleteButton.tag = indexPath.row
    cell.deleteButton.addTarget(self, action: #selector(deleteService(sender:)), for: UIControl.Event.touchUpInside)

    return cell


使用上面的代码,我可以添加 collectionview 单元格并能够以 JSON 格式存储数据,但是.. 如果我从这个 viewcontroller 移动并返回到这个 viewcontroller,那么 collectionview 不会显示,为什么?怎么了?请帮我写代码。我卡在这里很久了。

【问题讨论】:

尝试在主线程上重新加载集合视图,看看是否能解决问题。 @KeyhanKamangar,我尝试在主线程中重新加载.. 但相同.. 这是总代码.. 我用来显示 collectionview.. 但如果我从这个 VC 移动并回来我是.没有得到collectionview ..请帮忙..我被困在这里很久了 【参考方案1】:

您应该解决几个问题才能使其正常工作。我会给你每个理由。-

    您正在使用具有异步网络调用的postServiceCall() 方法加载数据。无法知道控制器何时完成将数据提取到arrImageItems 数组。因此,您应该使用完成处理程序。 现在,您正在后台线程的异步 dataTask 中更新 collectionView。大错。每当您有任何与 UI 相关的任务时,您都可以在 ma​​in 线程下进行。因此,您可以按照以下方式重构代码的 APIReqeustManager.sharedInstance.uploadMultipartFormData() 部分-

     APIReqeustManager.sharedInstance.uploadMultipartFormData(param: parameters, url: CommonUrl.edit_profile_images, image: imageProfile, fileName: "image", vc: self, isHeaderNeeded: true) (responseData) in
         print("edit profile result \(responseData)")
         if let result = responseData.dict?["result"] as? NSDictionary
             let success = result["status"] as? [String : Any]
             let message = success?["message"] as? String
             if message == "Success"
                 let image = result["image"] as? [String : Any]
                 let picId = image?["id"]
                 self.arrImageItems.append(ImageItemModel(title: self.titleTextfield.text, imgTitle: self.imageProfile, pic_id: picId as! Double))
                 DispatchQueue.main.async 
                     self.collectionView.reloadData()
                 
             
             else
                 DispatchQueue.main.async 
                     self.view.makeToast(CommonMessages.somethingWentWrong)
                 
             
         
     
    

    现在,除非您希望您的视图控制器仅在触发操作 imgtitleSaveBtn(_:) 时才在您的 collectionView 中显示数据,否则您每次都需要在您的视图控制器出现在屏幕上时获取数据。要解决这个问题,您应该在viewWillAppear(_:) 方法中获取数据,例如-


override func viewWillAppear(_ animated: Bool) 
    super.viewWillAppear(animated)
    postServiceCall()

现在,以上两个编辑应该可以解决您的问题,具体取决于您希望如何加载集合视图,但您的代码违反了相当多的编码标准。编码标准听起来像是一个派系,但相信我,如果你想在不破坏应用程序的情况下更新应用程序的功能,你会想遵循这些标准。以下只是一些提示-

    无论何时进行异步调用,都应考虑调用完成处理程序以返回数据。 应该检查你的方法,你正在危险地破坏单一责任主体。 在不止一个地方,您强制解包。馊主意。您需要您的系统具有故障保护功能,而不仅仅是崩溃。

更新 2:

设计模式的更新:

    以 MVC 模式划分您的代码。将ImageItemModel 类放在它自己的文件中。请参阅下图以了解设计-

    在 ImageCollectionViewCell 中自定义 collectionViewCell。假设您的自定义单元格只有插座。

class ImageCollectionViewCell: UICollectionViewCell 
    
    @IBOutlet weak var imgView: UIImageView!
    @IBOutlet weak var lblTitle: UILabel!
    @IBOutlet weak var deleteButton: UIButton!
        didSet
            deleteButton.addTarget(self, action: #selector(deleteService(_:)), for: .touchUpInside)
        
    

    // however this could easily be done with IBAction
    @objc func deleteService(_ sender: UIButton)
        
    

    更新postServiceCall 并使用完成处理程序将数据返回到您的控制器,这意味着当postServiceCall 执行完毕后,应根据成功或失败返回图像数组或空数组。然后控制器可以决定如何处理数据,在你的情况下更新 UI。经过几次重构,这里是更新后的控制器代码。
导入 UIKit 导入 EasyImagePicker 类 EditProfileImageViewController: UIViewController @IBOutlet weak var collectionView: UICollectionView! //用于故障排除 didSet //目的,从代码中做 collectionView.delegate = self collectionView.dataSource = 自我 @IBOutlet 弱 var titleTextfield:UITextField! 私有 var imageProfile : UIImage? 私有 var imagePicker : EasyImagePicker? // 你从未使用过这个变量。 var arrImageItems = [ImageItemModel]() // 每当视图控制器出现在屏幕上时,都会调用此方法。 覆盖 func viewWillAppear(_ animated: Bool) super.viewWillAppear(动画) reloadMyCollectionView() @IBAction func imgtitleSaveBtn(_ sender: Any) reloadMyCollectionView() 文件私有函数 reloadMyCollectionView() postServiceCall 中的图像 self.arrImageItems = 图片 DispatchQueue.main.async self.collectionView.reloadData() // 研究转义闭包以理解,为什么在这里需要它 fileprivate func postServiceCall(完成: @escaping(_ images: [ImageItemModel])->Void) // 不要强制展开,使用 guard let 安全地获取可选值 守卫让titleText = titleTextfield.text,titleText ==“”否则 返回 让参数= [“image_title”:titleText] APIReqeustManager.sharedInstance.uploadMultipartFormData(param: parameters, url: CommonUrl.edit_profile_images, image: imageProfile, fileName: "image", vc: self, isHeaderNeeded: true) (responseData) in print("编辑配置文件结果\(responseData)") //在本地范围内捕获数据并使用完成处理程序返回该数组 var imageItems = [] if let result = responseData.dict?["result"] as? NSDictionary 让成功 = 结果[“状态”] 作为? [字符串:任何] let message = success?["message"] as?细绳 如果消息==“成功” 让图像 = 结果 [“图像”] 作为? [字符串:任何] 让 picId = image?["id"] imageItems.append(ImageItemModel(title: self.titleTextfield.text, imgTitle: self.imageProfile, pic_id: picId as! Double)) self.completed(imageItems) // 如果结果中没有任何内容, //imageItems为空,否则会有imageItemModel数据 扩展 EditProfileImageViewController : UICollectionViewDelegate,UICollectionViewDataSource func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 返回 arrImageItems.count func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as? ImageCollectionViewCell cell.imgView.image = arrImageItems[indexPath.item].profileImage cell.lblTitle.text = arrImageItems[indexPath.row].title cell.deleteButton.tag = indexPath.row //cell.deleteButton.addTarget(self, action: #selector(deleteService(sender:)), for: UIControl.Event.touchUpInside) 返回单元格 别的 返回 UICollectionViewCell()

注意 postServiceCall 和 cellForItemAt 方法。

如果您仍然遇到同样的问题,那么您需要展示您的整个代码以获得进一步的帮助。

【讨论】:

我已根据您的回答更改了所有内容.. 但相同.. 从该 VC 转到另一个并返回后,collectionview 不会出现 这是我用来显示 collectionview 的代码。请帮助我卡在这里 由于 EasyImagePicker、ImageCollectionViewCell、APIReqeustManager 等自定义类,我无法运行您的代码。但是,collectionview 并没有消失。它显然在那里,但数据没有加载。在 numberOfItemsInSection 方法中放置一个断点,并在调试器中检查 arrImageItems.count 的值。如果 arrImageItems.count 为 0,那么您就知道数据不存在。 你在课堂上也有扩展,至少你发布的代码是这么说的。添加 ImageCollectionViewCell 和 APIReqeustManager 的代码。 还有你的 deleteService 功能。我在您的视图控制器中看不到任何 deleteService,如果 deleteService 方法不在 ViewController 中,那么您为什么采用目标操作方法而不是仅在 ImageCollectionViewCell 中创建 @IBAction

以上是关于当我迅速从该视图控制器移动时,为啥我的 Collectionview 单元格没有显示?的主要内容,如果未能解决你的问题,请参考以下文章

为啥当我返回时我的主视图控制器不会更新?

在表格视图控制器中添加容器视图时,如何将其移动到最底部? (迅速)

当我使用自动布局移动视图时,为啥 XCode 5 没有在情节提要中添加约束

当我的视图控制器上的按钮放置得太低时,为啥我的按钮停止工作?

离子视图未缓存,控制器重新加载

回到我的视图控制器时,为啥我的 iPhone UIToolBar 这么大?