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?
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()
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With