0

I am trying this for a couple of days now and haven't achieved anything yet. What I am trying to do is when a user picks a User item form the ViewController class, I want to save it in Realm and show it in the CollectionView of the SavedInterestsViewController class. I use a delegate pattern as suggested in this post How to access and refresh a UITableView from another class in Swift, but unfortunately I still receive nil, I guess because the GC removed the collectionView outlet already right? (please correct me if I misunderstood it). However, how can I get this to work by using a delegate pattern? Here is my code, this is the class where the user Picks a new User-item:

protocol ViewControllerDelegate {
func didUpdate(sender: ViewController)
}

class ViewController: UIViewController {

@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var collectionView: UICollectionView!
var delegate: ViewControllerDelegate?
let numberOfTweets = 5
let realm = try! Realm()

var image = UIImage()
var imageArray: [String] = []
var userArray: [User] = []

override func viewDidLoad() {
    super.viewDidLoad()
    
    collectionView.delegate = self
    collectionView.dataSource = self
    collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CollectionCell")
    searchBar.delegate = self
}

}

extension ViewController: UISearchBarDelegate {

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    print("One second...")
    let functionClass = NetworkingFunctions()
    var loopCount = 0
    functionClass.getWikipediaAssumptions(for: searchBar.text!) { [self] (articleArray) in
        self.userArray.removeAll()
        for x in articleArray {
            functionClass.performWikipediaSearch(with: x, language: WikipediaLanguage("en")) { (user) in
                self.userArray.append(user)
                collectionView.reloadData()
                loopCount += 1
            }
        }
    }
}
}

extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return userArray.count
}

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! CollectionViewCell
    let image = UIImage.init(data: userArray[indexPath.item].image as Data)
    cell.userImage.image = image
    cell.nameLabel.text = userArray[indexPath.item].name
    cell.userImage.layer.borderColor = image?.averageColor?.cgColor
    if userArray[indexPath.item].checked == false {
        cell.checkmark.isHidden = true
    } else {
        cell.checkmark.isHidden = false
    }
    return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    if userArray[indexPath.item].checked == false {
        userArray[indexPath.item].checked = true
        collectionView.reloadData()
        let newUser = User()
        newUser.image = userArray[indexPath.item].image
        newUser.name = userArray[indexPath.item].name
        newUser.checked = true
        try! realm.write {
            realm.add(newUser)
        }
        self.delegate = SavedInterestsViewController()
        self.delegate?.didUpdate(sender: self)
    }
    else {
        userArray[indexPath.item].checked = false
        collectionView.reloadData()
    }
}
}

extension ViewController: UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let width = UIScreen.main.bounds.width/3 - 10
    let height = width
    return CGSize(width: width, height: height)
}

}

class User: Object {

@objc dynamic var image: NSData = NSData()
@objc dynamic var name: String = ""
@objc dynamic var checked: Bool = false

}

... and this is the class where I want to show the selected item, after the User clicked on the 'Back' Button of the navigation controller of the ViewController class:

class SavedInterestsViewController: UIViewController, ViewControllerDelegate {
func didUpdate(sender: ViewController) {
    DispatchQueue.main.async {
        self.collectionView.reloadData()
    }
}

@IBOutlet weak var addButton: UIBarButtonItem!
@IBOutlet weak var collectionView: UICollectionView!
let realm = try! Realm()

var userArray: [User] = []

override func viewDidLoad() {
    super.viewDidLoad()

    collectionView.delegate = self
    collectionView.dataSource = self
    collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CollectionCell")
    fetchDataFromRealm()
    
}

@IBAction func addButtonPressed(_ sender: UIBarButtonItem) {
    performSegue(withIdentifier: "SavedToNew", sender: self)
}

func fetchDataFromRealm() {
    userArray.append(contentsOf: realm.objects(User.self))
    collectionView.reloadData()
}

}

extension SavedInterestsViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return userArray.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! CollectionViewCell
    let image = UIImage.init(data: userArray[indexPath.item].image as Data)
    cell.userImage.image = image
    cell.nameLabel.text = userArray[indexPath.item].name
    cell.userImage.layer.borderColor = image?.averageColor?.cgColor
    if userArray[indexPath.item].checked == false {
        cell.checkmark.isHidden = true
    } else {
        cell.checkmark.isHidden = false
    }
    return cell
}
}

extension SavedInterestsViewController: UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let width = UIScreen.main.bounds.width/3 - 10
    let height = width
    return CGSize(width: width, height: height)
}

}
yoKurt
  • 327
  • 1
  • 3
  • 8

1 Answers1

1

in your code you have lines

self.delegate = SavedInterestsViewController()
self.delegate?.didUpdate(sender: self)

but it do mostly nothing - you set the delegate to newly created class, didUpdate it - but I don't see any use of it - you don't present it in any way.

If I understand you right - you have SavedInterestsViewController, from it - you open ViewController, do something and when back to SavedInterestsViewController. (I can be wrong with your flow - correct me if so)

In this flow - you have delegate property in ViewController, but it must be of type SavedInterestsViewController. And you have to set it to SavedInterestsViewController when you open ViewController from it. And later in ViewController you have to call didUpdate method of delegate.

Denis Kozhukhov
  • 1,205
  • 8
  • 16
  • Yes the flow you described is correct. Okay, so I have to set self.delegate = SavedInterestsViewController.self, but what do you mean when you say that I have to set it to SavedInterestsViewController when I open it? – yoKurt Jan 09 '21 at 13:44
  • Now I tried: ` override func prepare(for segue: UIStoryboardSegue, sender: Any?) { let vc = segue.destination as! ViewController vc.delegate? = SavedInterestsViewController.self as! ViewControllerDelegate }` in the SavedViewControllerclass, but that didn't work. I didn't return nil, but the delegate method was never called. – yoKurt Jan 09 '21 at 14:12
  • It worked. I had to get rid of the question mark after the delegate property in the prepare for segue function and that was it. Thanks for your answer, that was really stressing me out! – yoKurt Jan 09 '21 at 14:43