2017-07-27 50 views
0

我想創建類似Facebook NewsFeed的東西,其中,我使用自定義UICollectionViewCell顯示來自JSON的數據(文本/圖像)。我有2個不同的API。一個用於文本,另一個用於圖像(每個單元格都沒有圖像)。重新加載UICollectionViewCell它有圖像

所以,首先,我從我的textAPI中獲取所有文本值,並重新加載myCollectionView。這是完美的。

現在的形象,我使用ImageFetcher獲取圖像,

func ImageFetcher(postId : NSNumber, completion : ((_ image: UIImage?) -> Void)!) { 

    var image = UIImage() 

    let urlString = "http://myImageAPI/Image/\(postId)" 
    let jsonUrlString = URL(string: urlString) 
    print(urlString) 
    URLSession.shared.dataTask(with: jsonUrlString!) { (data, response, error) in 

     do { 
      if let jsonData = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String:Any] { 
       if let images = jsonData["Image"] as? String { 
        if images == "" { 
         print("No Image") 
        } else { 
         let dataDecoded : Data? = Data(base64Encoded: images, options: .ignoreUnknownCharacters) 
         image = UIImage(data: dataDecoded!)! 
         completion(image) 
        } 
       } 
      } 
      else { 
       completion(nil) 
      } 
     } catch { 
      print(error.localizedDescription) 
     } 
    }.resume() 

} 

要到單元格中顯示圖像,

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 

// Displaying other elements with text 

DispatchQueue.main.async { 
     self.ImageFetcher(postId: self.myArray[indexPath.item].id!, completion: { (image) -> Void in 
      customCell.mainImage.image = image 
     }) 
// Declared "indexPaths" var indexPaths = [IndexPath]() 
// Added this lines 
     // let indexPath = IndexPath(item: indexPath.item, section: 0) 
     // self.indexPaths.append(indexPath) 
    } 

return customCell 
} 


override func viewDidAppear(_ animated: Bool) { 
    super.viewDidAppear(animated) 

    self.jsonParsing() 

} 
func jsonParsing() { 
    //Fetching text data from textAPI 

    //DispatchQueue.main.async { 
    //  self.collectionView.reloadItems(at: self.indexPaths) 
    //} 
} 

代碼工作沒有任何錯誤,但問題是圖片只有當我點擊它們時纔會出現。 (我可以在單元格中看到空的/白色的imageView,直到我點擊它。只要我點擊imageView圖像出現),我感覺它的東西與DispatchQueue.main.async,但不知道。

我不想在獲取圖像後重新加載整個collectionView。只是想重新加載那些有Image的單元。我在許多解決方案上找到了 collectionView.reloadItemsAtIndexPaths(myArrayOfIndexPaths) ,但不知道如何在這種情況下使其工作。任何人都可以在這裏幫我嗎?任何幫助都感激不盡。

+0

[從這裏開始引用。](https://stackoverflow.com/questions/28206492/refresh-certain-row-of-uitableview-based-on-int-in-swift )如果你仍然需要幫助,你可以問。 –

+0

謝謝!讓我試試看。 – iUser

+0

你可以稍微解釋一下 - > **問題是圖片只有當我點擊它們時纔會出現** –

回答

2

你可以試試嗎?

DispatchQueue.main.async { 
     customCell.mainImage.image = image 
} 

代替

customCell.mainImage.image = image 

=====================更新============ ==========

我最終幫助Snehal不僅僅是圖像加載問題,還有一些其他問題與集合視圖和圖像緩存。我建議他使用像SDWebImage這樣的第三方庫,但發現他的api在響應中返回圖像爲base64字符串。所以我就繼續清理他的代碼並編寫代碼,我認爲這可能對他有幫助。

import UIKit 

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { 

    let imageView = UIImageView() 
    lazy var collectionView: UICollectionView = { 
     let layout = UICollectionViewFlowLayout() 
     layout.minimumInteritemSpacing = 10 
     layout.minimumLineSpacing = 10 
     layout.scrollDirection = .vertical 

     let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) 
     collectionView.delegate = self 
     collectionView.dataSource = self 
     collectionView.register(CustomCell.self, forCellWithReuseIdentifier: NSStringFromClass(CustomCell.self)) 
     collectionView.backgroundColor = .clear 
     return collectionView 
    }() 


    override func viewDidLoad() { 
     super.viewDidLoad() 
     view.addSubview(collectionView) 
    } 

    override func viewWillLayoutSubviews() { 
     super.viewWillLayoutSubviews() 
     collectionView.frame = view.bounds 
    } 

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 
     return 50 
    } 

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 
     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(CustomCell.self), for: indexPath) as! CustomCell 
     cell.imageUrl = "http://myImageAPI/Image/\(postId)" 
     return cell 
    } 


    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 
     return CGSize(width: collectionView.frame.size.width - 2 * 20, height: 100) 
    } 

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 

} 
} 


class CustomCell: UICollectionViewCell { 

    let imageView = UIImageView() 
    var imageUrl: String? { 
     didSet { 
      if let imageUrl = imageUrl, let url = URL(string: imageUrl) { 
       dataTask = imageView.loadImage(url: url) 
      } 

     } 
    } 

    var dataTask: URLSessionDataTask? 

    override init(frame: CGRect) { 
     super.init(frame: frame) 

     backgroundColor = .white 
     imageView.backgroundColor = UIColor.lightGray 
     imageView.contentMode = .scaleAspectFit 
     contentView.addSubview(imageView) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    override func prepareForReuse() { 
     super.prepareForReuse() 
     dataTask?.cancel() 
     imageView.image = nil 
    } 

    override func layoutSubviews() { 
     super.layoutSubviews() 
     imageView.frame = bounds 
    } 
} 


extension UIImageView { 
    @discardableResult func loadImage(url: URL) -> URLSessionDataTask? { 
     if let image = ImageLoadManager.manager.cachedImages[url.absoluteString] { 
      self.image = image 
      return nil 
     } 
     let task = URLSession.shared.dataTask(with: url) { (data, response, error) in 
      do { 
       guard let data = data else { 
        return 
       } 
       if let jsonData = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:Any] { 
       if let images = jsonData["PostImage"] as? String {// Pase the Base64 image string 
        if images == "" { 
          print("No Image") 
        } else { 
         if let dataDecoded = Data(base64Encoded: images, options: .ignoreUnknownCharacters), let decodedImage = UIImage(data: dataDecoded) { 
          DispatchQueue.main.async { 
        ImageLoadManager.manager.cachedImages[url.absoluteString] = decodedImage 
        self.image = decodedImage 
           } 
         } 
        } 
       } 
      } 
      else { 
        DispatchQueue.main.async { 
         self.image = nil 
        } 
      } 
      } catch { 
       print(error.localizedDescription) 
      } 
     } 
     task.resume() 
     return task 
    } 
} 

class ImageLoadManager { 
    static let manager = ImageLoadManager() 
    var cachedImages = [String: UIImage]() 
} 
+0

Omg! :|這是問題。啊..謝謝你,哥們,你的幫助! – iUser

+0

嘿HMHero,我再次得到同樣的問題。我更新了我的代碼。我正在使用緩存的圖像來顯示這個時間。這次圖像不會顯示,直到我滾動collectionView。一旦我滾動所有的圖像都在正確的地方。 – iUser

+0

@Snehal可能是同一個問題。這個想法是,你必須確保你將圖像設置爲圖像視圖的地方,它必須在主線程中。 – HMHero

0

更好的辦法做到這就像作出這樣的類,它包含的圖像和類似 類AnyName {VAR URL文本變量的網址模型:字符串? var desc:String?

init(urlValue: String?, descValue:String?){ 
    url = urlValue 
    desc = descValue 
} 

} 

現在,在您的ViewController使上面的類名 VAR項目= AnyName 的陣列現在,通過第一API,打你能爲這個數組中的文本設定值,並傳遞到的CollectionView和文字負荷細胞,然後你可以更改網址的陣列值並輕鬆地重新加載collectionview