3

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
    }
user3708224
  • 1,229
  • 4
  • 19
  • 37
  • What is the exact issue "am not able to load the CustomImageView:UIImageView from that same selectedIndexPath using the same process and code logic"? – shallowThought Jul 10 '17 at 09:10
  • I have successfully passed and displayed the nameString and locationString values between classes to be displayed in the header cell based on the cell selected in the first main collectionViewController. But passing the profileImageUrl string does not load the selected cells profileImage (which is the CustomImageView: UIImageView class (the placeholder image always appears). – user3708224 Jul 10 '17 at 13:44
  • What is `profileImageUrl`? – shallowThought Jul 11 '17 at 07:22
  • I don't see anywhere in your code that you actually call `loadImageUsingCacheWithUrlString` or `loadImageUsingUrlString`. – Scriptable Jul 11 '17 at 12:45
  • yes, forgot to add that. I added that cell class to original code post. thanks – user3708224 Jul 11 '17 at 13:51
  • and I have tried to call that same method when loading the 2nd collectionView with the header cell to display passed profileImageUrl in the CustomImageView class. – user3708224 Jul 12 '17 at 13:43

1 Answers1

0

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
}
user3708224
  • 1,229
  • 4
  • 19
  • 37