Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS reloading a UITableView from a Swift class/object

I am trying to build a object oriented iOS app and I am having problems calling a table reload (ui interaction) from one of my swift class files.

If I am working without objects and write all that stuff in my InterfaceController's viewDidLoad method everything works... but not if I put that into classes.

I am using an asynchronous request in order to load json data from a webservice. After receiving the data I am using this data as data source for my table view. It seems the tableview is initialized after startup with no data, so it is neccessary to call reload() on the tableview after finishing the async request.

So here are the details:

Main TableController

import UIKit;


class DeviceOverview: UITableViewController {

@IBOutlet var myTableView: UITableView!

var myDevices = Array<String>();
var myDevicesSection = NSMutableDictionary()
var deviceObjects = Array<NSDictionary>();
var mappingSectionIndex = Array<String>();
var sharedUserDefaults = NSUserDefaults(suiteName: "group.barz.fhem.SharingDefaults")

// THIS IS AN ATTEMPT TO give the class itself as PARAMETER
// ALSO TRIED TO USE myTableView (IBOutlet)
var fhem :FHEM  = FHEM(tableview : self)

override func viewDidLoad() {

    super.viewDidLoad()

}


override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return self.fhem.sections.count
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    var devicesInSection : Array<NSDictionary> = self.fhem.sections[self.fhem.mappingSectionIndex[section]] as! Array<NSDictionary>
    return devicesInSection.count;
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("device", forIndexPath: indexPath) as! TableViewCell
    let sectionName : String = fhem.mappingSectionIndex[indexPath.section]
    if let devices : Array<NSDictionary> =   self.fhem.sections.objectForKey(sectionName) as? Array<NSDictionary> {
        let device = devices[indexPath.row]
        var alias : NSString?;
        if let attr : NSDictionary = device.objectForKey("ATTR") as? NSDictionary {
            alias = attr.objectForKey("alias") as? String
        }
        if (alias != nil) {
            cell.deviceLabel.text = alias as? String
        }else{
            if let deviceName : String = device.objectForKey("NAME") as? String {
                cell.deviceLabel.text = deviceName
            }
        }
    }
    return cell
}

FHEM Class

import UIKit


class FHEM: NSObject {

var devices : [NSDictionary]
var sections : NSMutableDictionary
var deviceNames : [String]
var mappingSectionIndex : [String]
var myTableViewController : DeviceOverview

init(tableview : DeviceOverview){
    self.devices = Array<NSDictionary>()
    self.sections = NSMutableDictionary()
    self.deviceNames = Array<String>()
    self.mappingSectionIndex = Array<String>()
    self.myTableViewController = tableview
    super.init()

    let url = NSURL(string: "xyz");
    var request = NSURLRequest(URL: url!);

    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
        (response, data, error) in
        if let jsonData: NSData? = data {
            // do some great stuff
            //
            // this is an attempt to call the table view to reload
            self.myTableViewController.myTableView.reloadData()
        }
    }
}
}

It throws compile errors if I try to put the self variable into the constructor of my constructor

var fhem :FHEM  = FHEM(tableview : self)

It also does not work if I try to put the UITableView directly into the constructor

var fhem :FHEM  = FHEM(tableview : myTableView)

Am I walking along complete wrong path using objects and interacting with the ui?

like image 967
Barzille Avatar asked Apr 22 '15 06:04

Barzille


2 Answers

You can just post a Notification when your async task finishes:

NSNotificationCenter.defaultCenter().postNotificationName("refreshMyTableView", object: nil)

Add an observer to that notification to your DeviceOverview class method viewDidLoad:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshList:", name:"refreshMyTableView", object: nil) 

and add the method that will be fired at your DeviceOverview class

func refreshList(notification: NSNotification){
    myTableView.reloadData()
}
like image 77
Leo Dabus Avatar answered Nov 12 '22 09:11

Leo Dabus


Hi You can use Notification as suggested in Above answers otherwise you can use delegation to resolve this problem

Delegate is doing something like that you done but in easy manner.

Here you pass table view controller in you custom class.this thing you can do with delegate. create custom delegate method in your custom class. set delegate with table view controller object.

here you don't required to take IBOutlet of your table view because your controller inherited from table view controller so it's view is table view

import UIKit


class DeviceOverview: UITableViewController,FHEMDelegate {

    @IBOutlet var myTableView: UITableView!

    var myDevices = Array<String>();
    var myDevicesSection = NSMutableDictionary()
    var deviceObjects = Array<NSDictionary>();
    var mappingSectionIndex = Array<String>();
    var sharedUserDefaults = NSUserDefaults(suiteName: "group.barz.fhem.SharingDefaults")
    var fhem :FHEM?
    // THIS IS AN ATTEMPT TO give the class itself as PARAMETER
    // ALSO TRIED TO USE myTableView (IBOutlet)


    override func viewDidLoad() {

        super.viewDidLoad()
        fhem = FHEM ()
        fhem?.delegate = self

    }


    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1;
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//        var devicesInSection : Array<NSDictionary> = self.fhem!.sections[self.fhem!.mappingSectionIndex[section]] as Array<NSDictionary>

        return 5;
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("device", forIndexPath: indexPath) as UITableViewCell
        let sectionName : String = fhem!.mappingSectionIndex[indexPath.section]
        if let devices : Array<NSDictionary> =   self.fhem!.sections.objectForKey(sectionName) as? Array<NSDictionary> {
            let device = devices[indexPath.row]
            var alias : NSString?;
            if let attr : NSDictionary = device.objectForKey("ATTR") as? NSDictionary {
                alias = attr.objectForKey("alias") as? String
            }
            if (alias != nil) {
              //  cell.deviceLabel.text = alias as? String
            }else{
                if let deviceName : String = device.objectForKey("NAME") as? String {
                  //  cell.deviceLabel.text = deviceName
                }
            }
        }
        return cell
    }
    func reloadDataOfTable()
    {
        self.tableView.reloadData()
    }
}

FHEM

import UIKit
protocol FHEMDelegate{

   func reloadDataOfTable()
}
class FHEM : NSObject {
    var devices : [NSDictionary]
    var sections : NSMutableDictionary
    var deviceNames : [String]
    var mappingSectionIndex : [String]
    //var myTableViewController : DeviceOverview
    var delegate :FHEMDelegate?

 override init(){
        self.devices = Array<NSDictionary>()
        self.sections = NSMutableDictionary()
        self.deviceNames = Array<String>()
        self.mappingSectionIndex = Array<String>()
        self.delegate = nil
        super.init()

    let url = NSURL(string: "http://google.com");
        var request = NSURLRequest(URL: url!);

        NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
            (response, data, error) in
            if let jsonData: NSData? = data {
                // do some great stuff
                //
                // this is an attempt to call the table view to reload
              self.delegate?.reloadDataOfTable()
            }
        }
    }
}

Here in FHEM class create one custom delegate method reloadDataOfTable that implement in your viewcontroller class so when got response of code it call that method and this method (reloadDataOfTable) content code for reload table data.

like image 44
user1548843 Avatar answered Nov 12 '22 09:11

user1548843