Reputation: 18188
I am working with the following class which successfully loads a row to the UITableView.
import UIKit
import ResearchKit
enum Activity: Int {
case Demographics
static var allValues: [Activity] {
var idx = 0
return Array(anyGenerator{ return self.init(rawValue: idx++)})
}
var title: String {
switch self {
case .Demographics:
return "Demographics"
}
}
var subtitle: String {
switch self {
case .Demographics:
return "Demographics Survey"
}
}
}
class ActivityViewController: UITableViewController {
// MARK: UITableViewDataSource
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard section == 0 else { return 0 }
return Activity.allValues.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("activityCell", forIndexPath: indexPath)
if let activity = Activity(rawValue: indexPath.row) {
cell.textLabel?.text = activity.title
cell.detailTextLabel?.text = activity.subtitle
if (activity.title == "Demographics"){
if (Data().is_demo_complete()){
cell.textLabel?.textColor = UIColor.lightGrayColor()
cell.detailTextLabel?.textColor = UIColor.lightGrayColor()
cell.userInteractionEnabled = false
}
}
}
return cell
}
func reloadtable(){
self.tableView.reloadData()
}
// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
guard let activity = Activity(rawValue: indexPath.row) else { return }
let taskViewController: ORKTaskViewController
switch activity {
case .Demographics:
taskViewController = ORKTaskViewController(task: DemoTask, taskRunUUID: NSUUID())
}
taskViewController.delegate = self
navigationController?.presentViewController(taskViewController, animated: true, completion: nil)
}
}
I have another class called Data
where I store all communications to my server. The idea is that I have to check some data on the server to know whether or not to grey out and disable one of the rows in the tableView. From the data class, when the server call is completed and successful, i do this:
dispatch_async(dispatch_get_main_queue(), { () -> Void in
ActivityViewController().reloadtable()
})
I have confirmed, that successfully calls the reloadtable()
function, in which it runs self.tableView.reloadData()
. The place I am stuck is that after that, the tableView doesn't actually reload. I can tell because I put a breakpoint on the line that says if let activity = Activity(rawValue: indexPath.row) {
and the breakpoint does not get triggered a second time, even though I can confirm that the reloadtable()
function is indeed triggered. What am I doing wrong here, why isn't the table being reloaded? Thanks!
EDIT
Here is the Data
class:
class Data: NSObject, NSURLSessionDelegate {
var unique_id = UIDevice.currentDevice().identifierForVendor!.UUIDString;
var demo_complete = false
func check_demo_complete(){
let request = NSMutableURLRequest(URL: NSURL(string: "https://www.myurl.com/is_demo_complete.php")!)
request.HTTPMethod = "POST"
let postString = "unique_id=\(unique_id)&pass=somepass"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let task = session.dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
if ( responseString == "true" ) {
self.demo_complete = true
print ("Demo has been completed")
dispatch_async(dispatch_get_main_queue(), { () -> Void in
ActivityViewController().reloadtable()
})
}
}
task.resume()
}
func is_demo_complete() -> Bool{
return self.demo_complete
}
}
Upvotes: 0
Views: 101
Reputation: 540
The problem is the ActivityViewController().reloadtable()
call. This creates a new ActivityViewController
each time your Data
class downloaded data. It is important that you'd only call reloadtable()
on the same ActivityViewController
instance that already exists (and that is displayed on screen).
One good (basic but simple) solution would be to do the following refactoring :
func check_demo_complete(completion:(Bool -> ()){
// your network call
dispatch_async(dispatch_get_main_queue()) {
if ( responseString == "true" ) {
completion(true)
}
else {
completion(false)
}
// or, simpler : completion(responseString == "true")
}
}
That way, by calling check_demo_complete()
, you'd be obligated to pass a closure :
if (activity.title == "Demographics"){
Data().check_demo_complete() { [weak self] success in
if success {
// change your textColors etc
self?.tableView.reloadData()
}
}
}
Again, this is a basic solution that should work. The important lesson to learn is : don't create new instance of classes each time you need them.
Upvotes: 1