Ameya Vichare Ameya Vichare - 4 months ago 18
Swift Question

Swift: How to access a mutable array of strings from one UIViewController to a TableView cell file

I have one view controller named TableViewController and another customised cell called feed.swift
The cells are getting reused properly and I have put tags on various buttons as I wan't to know what button of what feed is pressed on.
In my cellForRowAtIndexPath I'm populating my username with json that I have parsed. It looks like this

cell.username.text = username[indexPath.row]
output-> ["andre gomes", "renato sanchez", "renato sanchez"]


Then I have tagged my username button like this

cell.usernamePress.tag = indexPath.row


This is going on in my TableViewController

In my feed.swift I'm checking if a button is pressed and printing out the tag assigned to that button

@IBAction func usernameBut(sender: AnyObject) {
print(usernamePress.tag)
}
output-> 2


Now I need to access the username array of TableViewController in feed.swift and do something like username[usernamePress.tag]

I tried making a global.swift file but I'm not able to configure it for an array of strings.

import Foundation

class Main {
var name:String
init(name:String) {
self.name = name
}
}
var mainInstance = Main(name: "hello")


Even after doing this I tried printing mainInstance.name and it returned hello even after changing it. I want a solution where the array of strings holds the values I set in TableViewController and I can be able to use them in feed.swift
Any suggestions would be welcome! I'm sorry if there are any similar question regarding this but I'm not able to figure out how to use it for a mutable array of strings

Answer

I suggest you don't use the array directly in your FeedCell but instead return the press-event back to your TableViewController where you handle the event. According to the MVC Scheme, which is the one Apple requests you to use (checkout Apples documentation), all your data-manipulation should happen in the Controller, which then prepares the Views using this data. It is not the View that is in charge to display the right values.

To solve your problem I would choose to pass back the press-event via the delegation-pattern, e.g. you create a FeedCellDelegate protocol that defines a function to be called when the button is pressed:

protocol FeedCellDelegate {
    func feedCell(didPressButton button: UIButton, inCell cell: FeedCell)
}

Inside your FeedCell you then add a delegate property, which is informed about the event by the View:

class FeedCell {
    var delegate: FeedCellDelegate?
    ...
    @IBAction func pressedUsernameButton(sender: UIButton) {
        delegate?.feedCell(didPressButton: sender, inCell: self)
    }
}

If your TableViewController then conforms to the just defined protocol (implements the method defined in there) and you assign the ViewController as the View's delegate, you can handle the logic in the Controller:

class TableViewController: UITableViewController, FeedCellDelegate {
     ...
     override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
         let cell = tableView.dequeueReusableCellWithIdentifier("FeedCell", forIndexPath: indexPath) as! FeedCell
         cell.delegate = self
         // Further setup
         return cell
     }

     func feedCell(didPressButton button: UIButton, inCell cell: FeedCell) {
         guard let indexPath = tableView.indexPathForCell(cell) else { return }

         // Do your event-handling
         switch (button.tag) {
         case 2: print("Is username button")
         default: print("Press not handled")
         }
     }
}

As you might recognize I changed your class name. A Feed sounds more like a Model-class whereas FeedCell implies its role to display data. It makes a programmer's life way easier if you choose self-explaining names for your classes and variables, so feel free to adapt that. :)