suisied
suisied

Reputation: 426

getting a value inside a code block to function return in swift

I am working with parse, I am trying to return row.count of a table and output it to a label.text.

func numberOfPostedJobsCount() -> Int{
    var postsCount: Int?
    var query = PFQuery(className: "Post")
    if let user = PFUser.currentUser() {
        query.whereKey("user", equalTo: user)
    }
    query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error) -> Void in
        if error == nil {
            //query succeeded
            print("\(objects?.count)")
        } else {
            print("\(error)")
        }
    }

    return postsCount!
}

The code inside viewDidLoad() is

numberOfPostedJobs.text = String(numberOfPostedJobsCount())

error : fatal error: unexpectedly found nil while unwrapping an Optional value

Edit 1: I tried adding a public or private variable but it didn't work.

func numberOfPostedJobsCount() -> (Int) {
    var num1: Int = 0
    var query = PFQuery(className: "Post")
    if let user = PFUser.currentUser() {
        query.whereKey("user", equalTo: user)
    }
    query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error) -> Void in

        if error == nil {
            //query succeeded
            print("\(objects?.count)")
            num1 = (objects?.count)!
            print(num1)
        } else {
            print("\(error)")
        }
    }

    return num1
}

Upvotes: 0

Views: 151

Answers (2)

Ankit Kumar Gupta
Ankit Kumar Gupta

Reputation: 219

You can use semaphores to make a asynchronous method to work synchronously:

A Sample method for your problem statement

func test()->Int {
    var postsCount: Int?
    let sema:dispatch_semaphore_t = dispatch_semaphore_create(0)

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) { () -> Void in
        postsCount = 100
        dispatch_semaphore_signal(sema)
    }

    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)
    return postsCount!
}

for above code:

func numberOfPostedJobsCount() -> Int{
var postsCount: Int?
var query = PFQuery(className: "Post")
let sema:dispatch_semaphore_t = dispatch_semaphore_create(0)
if let user = PFUser.currentUser() {
    query.whereKey("user", equalTo: user)
}
query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error) -> Void in
    if error == nil {
        //query succeeded
        postsCount = objects?.count
        dispatch_semaphore_signal(sema)
        print("\(objects?.count)")
    } else {
        postsCount = 0
        dispatch_semaphore_signal(sema)
        print("\(error)")
    }
}
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)
return postsCount!
}

Upvotes: 0

vadian
vadian

Reputation: 285072

The reason is that postsCount is declared but never be initialized, so it's nil when you unwrap it.

Be aware that the function findObjectsInBackgroundWithBlock works asynchronously, that means the block is called always after the return statement. In this block you have to update your data source and/or the UI.

Edit:

Return Void from your function and use a completion handler for example

func numberOfPostedJobsCount(completion: (Int) -> ()) {
  var query = PFQuery(className: "Post")
  if let user = PFUser.currentUser() {
    query.whereKey("user", equalTo: user)
  }
  query.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error) -> Void in

    if error == nil {
      //query succeeded
      print("\(objects?.count)")
      let num1 = (objects?.count)!
      completion(num1)
    } else {
      print("\(error)")
       completion(0)
    }
  }
}

You call the function this way

numberOfPostedJobsCount() { (postsCount) -> () in
  numberOfPostedJobs.text = String(postsCount)
}

Upvotes: 1

Related Questions