I am having a lot of trouble loading a CustomImageView: UIImageView in a detail viewController based on the selectedIndexPath of a collectionViewCell. I have successfully passed and loaded the UILabels and UITextViews, but am not able to load the CustomImageView:UIImageView from that same selectedIndexPath using the same process and code logic. I believe it has something to do with clearing or resetting my image cache, but not sure where or exactly what code to execute to do this. Sorry for any excess code, just want to be thorough. Thanks for any help or direction!
// model object classes storing values from Firebase
class CurrentPlanner: SafeJsonObjectPlanner {
var name: String?
var profileImageUrl: String?
var planningPlace: String?
init(dictionary: [String: AnyObject]) {
self.name = dictionary["addedBy"] as? String
self.profileImageUrl = dictionary["profileImageUrl"] as? String
self.planningPlace = dictionary["planning"] as? String
}
}
// CustomImageView: UIImageView extension that populates the first collectionViewController
let imageCache = NSCache<NSString, UIImage>()
class CustomImageView: UIImageView {
var imageUrlString: String?
func loadImageUsingUrlString(_ urlString: String) {
imageUrlString = urlString
let url = URL(string: urlString)
image = nil
if let imageFromCache = imageCache.object(forKey: urlString as NSString) {
self.image = imageFromCache
return
}
URLSession.shared.dataTask(with: url!, completionHandler: { (data, respones, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async(execute: {
let imageToCache = UIImage(data: data!)
if self.imageUrlString == urlString {
self.image = imageToCache
}
imageCache.setObject(imageToCache!, forKey: urlString as NSString)
})
}).resume()
}
}
extension UIImageView {
func loadImageUsingCacheWithUrlString(_ urlString: String) {
self.image = nil
//check cache for image first
if let cachedImage = imageCache.object(forKey: urlString as NSString) {
self.image = cachedImage
return
}
//otherwise fire off a new download
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
//download hit an error so lets return out
if let error = error {
print(error)
return
}
DispatchQueue.main.async(execute: {
if let downloadedImage = UIImage(data: data!) {
imageCache.setObject(downloadedImage, forKey: urlString as NSString)
self.image = downloadedImage
}
})
}).resume()
}
}
// planning cell class in the first collectionView
class BasePlanningCell: BaseCell2 {
var currentPlanners = [CurrentPlanner]()
var currentPlanner: CurrentPlanner? {
didSet {
setupProfileImage()
}
}
fileprivate func setupProfileImage() {
if let profileImageUrl = currentPlanner?.profileImageUrl {
userProfileImageView.loadImageUsingCacheWithUrlString(profileImageUrl)
}
}
// tapped cell class in first collectionView - call delegate method
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("cell tapped")
// cell delegate method called from collectionViewController
travelersFeedVC?.showPlanningViewDetailView(indexPath: indexPath)
}
// first collectionViewController class - method performed on cell tap
func showPlanningViewDetailView(indexPath: IndexPath) {
let plannersDetailVC = PlanningPlaceDetailsVC()
plannersDetailVC.profileImageUrl = plannedPlaces[indexPath.row].profileImageUrl!
print(plannersDetailVC.profileImageUrl!)
show(plannersDetailVC, sender: self)
}
// 2nd DetailViewController class
var nameString: String!
var locationString: String!
var profileImageUrl: String!
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
switch indexPath.item {
case 0:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PlanningDetailViewCells", for: indexPath) as! PlanningDetailViewCells
cell.myMethod(str: nameString)
cell.getLocationMethod(str: locationString)
cell.getProfileImageMethod(str: profileImageUrl)
return cell
case 1:
// ...
case 2:
// ...
default:
// ...
}
}
// 2nd DetailViewControllers Cells Delegate Class
func myMethod(str : String){
nameString = str
print("var : \(nameString)")
planningCellHeader?.titleLabel.text = nameString
}
func getLocationMethod(str : String){
locationString = str
print("var : \(String(describing: locationString))")
planningCellHeader?.locationTextView.text = locationString
}
func getProfileImageMethod(str : String){
profileImageUrl = str
print("var : \(String(describing: profileImageUrl))")
planningCellHeader?.userProfileImageView.imageUrlString = profileImageUrl
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
switch indexPath.section {
case 0:
switch indexPath.item {
case 0:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "headerId", for: indexPath) as! PlanningCellHeader
cell.myMethod(str: nameString)
cell.getLocationMethod(str: locationString)
cell.getProfileImageMethod(str: profileImageUrl)
return cell
case 1:
// ...
default:
// ...
}
default:
// ...
}
}
// headerCell class that holds the views
var nameString: String?
var locationString: String?
var profileImageUrl: String?
let titleLabel: UILabel = {
let label = UILabel()
// ...
return label
}()
let locationTextView: UITextView = {
let textView = UITextView()
// ...
return textView
}()
let userProfileImageView: CustomImageView = {
let imageView = CustomImageView()
// ...
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
titleLabel.text = nameString
locationTextView.text = locationString
userProfileImageView.imageUrlString = profileImageUrl
setupViews()
}
func myMethod(str : String){
nameString = str
print("var : \(String(describing: nameString))")
titleLabel.text = nameString
}
func getLocationMethod(str : String){
locationString = str
print("var : \(String(describing: locationString))")
locationTextView.text = locationString
}
func getProfileImageMethod(str : String){
profileImageUrl = str
print("var : \(String(describing: profileImageUrl))")
// userProfileImageView.image = UIImage(named: "meAndDuncan")
userProfileImageView.imageUrlString = profileImageUrl
}
I figured it out on my own. Maybe self explanatory, but I had to convert the imageUrlString back to Data(contentsOf: url!) in my getProfileImageMethod(str : String) as seen below:
func getProfileImageMethod(str : String){
profileImageUrl = str
print("var : \(String(describing: profileImageUrl))")
// added the code below and it worked!
var imageUrlString: String?
imageUrlString = profileImageUrl
let url = URL(string: imageUrlString!)
let data = try? Data(contentsOf: url!)
let image: UIImage = UIImage(data: data!)!
userProfileImageView.image = image
}