1

My problem arises when I want to populate data from my mysql database into a class object. I am trying to return an array of objects and it returns nil and then it fills itself somehow. How can I make it fill before returning the blank array?

Here is my code and a screenshot of code output

import Foundation

class Research
{
  var mainResearchImageURL:String = ""
  var userProfileImageURL:String = ""
  var caption:String = ""
  var shortDescription:String = ""

  init(mainResearchImageURL :String, userProfileImageURL:String, caption:String, shortDescription:String)
  {

    self.mainResearchImageURL = mainResearchImageURL
    self.userProfileImageURL = userProfileImageURL
    self.caption = caption
    self.shortDescription = shortDescription
  } 

  class func downloadAllResearches()->[Research]
  {
    var researches = [Research]()
    let urlString = "http://localhost/test/index.php"
    let request = NSMutableURLRequest(URL: NSURL(string: urlString)!)
    request.HTTPMethod = "POST"
    let postString = "action=listresearches"
    request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error in
        if (error == nil) {

            do {
                let json =  try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSArray
                //let dictionary = json!.firstObject as? NSDictionary

                var counter:Int = 0;
                for line in json!{
                    let researchData = line as! NSDictionary
                    let researchLineFromData = Research(mainResearchImageURL: researchData["research_mainImageURL"] as! String, userProfileImageURL: researchData["research_creatorProfileImageURL"] as! String, caption: researchData["research_caption"] as! String, shortDescription: researchData["research_shortDescription"] as! String)
                   researches.append(researchLineFromData) //researches bir dizi ve elemanları Research türünde bir sınıftan oluşuyor.

                    counter += 1
                    print ("counter value \(counter)")
                    print("array count in loop is = \(researches.count)")
                }
            }catch let error as NSError{
                print(error)
            }
        } else {
            print(error)
        }})
    task.resume()

    print("array count in return is = \(researches.count)")
    return researches
  }
}

And this is the output:

enter image description here

halfer
  • 19,824
  • 17
  • 99
  • 186
  • The issue you are having is not an "issue". Swift is doing you a favor by performing any web requests in the background and not holding up your application while it finishes that up. You just have to handle it accordingly. I would look into dispatch groups. They will allow you to execute code once a task is complete. Check this answer here: http://stackoverflow.com/questions/35906568/wait-until-swift-for-loop-with-asynchronous-network-requests-finishes-executing/35906703#35906703 – Geoherna May 18 '16 at 18:53

2 Answers2

0

add this on you completionHandler ( it works if you update a view)

dispatch_async(dispatch_get_main_queue(), {
    if (error == nil) { ...... }
})

Advice 1:

return the task and use a completion param in your method, you can cancel the task if it's too slow.

Advice 2 : Use alamofire and swiftyJson framework

Andy
  • 30,088
  • 6
  • 78
  • 89
Arnold Mapps
  • 190
  • 3
  • 11
0

What happen here is that you are returning the value before finish (remember that the call is Asynchronous), you can make something like this:

class func downloadAllResearches(success:([Research])->Void,failure:(String)->Void)
{
    var researches = [Research]()
    let urlString = "http://localhost/test/index.php"
    let request = NSMutableURLRequest(URL: NSURL(string: urlString)!)
    request.HTTPMethod = "POST"
    let postString = "action=listresearches"
    request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error in
    if (error == nil) {

        do {
            let json =  try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSArray
            //let dictionary = json!.firstObject as? NSDictionary

            var counter:Int = 0;
            for line in json!{
                let researchData = line as! NSDictionary
                let researchLineFromData = Research(mainResearchImageURL: researchData["research_mainImageURL"] as! String, userProfileImageURL: researchData["research_creatorProfileImageURL"] as! String, caption: researchData["research_caption"] as! String, shortDescription: researchData["research_shortDescription"] as! String)
               researches.append(researchLineFromData) //researches bir dizi ve elemanları Research türünde bir sınıftan oluşuyor.

                counter += 1
                print ("counter value \(counter)")
                print("array count in loop is = \(researches.count)")
            }
            success(researches)
        }catch let error as NSError{
            print(error)
            failure("Can be extract from NSERROR")
        }
    } else {
        print(error)
        failure("Error - Can be extract for NSERROR")
    }})
task.resume()

}

And for call this Fuction use something like this:

    Research.downloadAllResearches({ (objects:[Research]) -> Void in
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            //Do whatever you like with the content
        })
    }) { (failureLiteral:String) -> Void in

    }
  • Did not work for me. When I try to call the function like you Xcode warns me with a red flag and says "Expected declaration". – Murat Ekici May 19 '16 at 05:30
  • Can you take a print screen? Mmm did you put the last } in the method (downloadAllResearches), I inadvertently left out (in the block code) – José Roberto Abreu May 19 '16 at 13:33