Подтвердить что ты не робот

Получение данных после завершенияHandler в Swift в NSURLConnection

Я пытаюсь написать функцию, которая будет выполнять асинхронный запрос GET, и вернуть ответ (как любой тип данных, но здесь он является NSData).

Этот вопрос основан на: Как использовать NSURLConnection completeHandler с быстрым

func getAsynchData() -> NSData {
    var dataOutput : NSData
    let url:NSURL = NSURL(string:"some url")
    let request:NSURLRequest = NSURLRequest(URL:url)
    let queue:NSOperationQueue = NSOperationQueue()

    NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
            /* this next line gives the below error */
            dataOutput = data
    })
    return dataOutput
}

но я получаю сообщение об ошибке:

error: variable 'dataOutput' captured by a closure before being initialized

Я попробовал вернуть значение из функции завершенияHandler, но для этого требуется возврат void, что жутко напоминает мне о моей надежде решить эту проблему без помощи...: D

Я посмотрел: Как использовать завершение закрытия Handler с возвратом в Swift? но это на самом деле не отвечает на мой вопрос. Моя цель здесь - получить данные из моего асинхронного запроса из блока, для использования в другом месте моего кода. Должен ли я выполнять всю работу с этим запросом в этом блоке и не извлекать данные?

Спасибо!

ИЗМЕНИТЬ

ok, поэтому у меня есть вариант, который, как я думаю, может работать, но мне это кажется неправильным. Может ли кто-нибудь сказать мне, является ли это наилучшим способом достижения моей цели?

func doThingsWithData( data: NSData ) -> String {
    /* code to extract string from NSData */
    return somestring
}
func getAsynchData() {
    let url:NSURL = NSURL(string:"some url")
    let request:NSURLRequest = NSURLRequest(URL:url)
    let queue:NSOperationQueue = NSOperationQueue()

    NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
            /* this next line gives the below error */
            doThingsWithData(data)
    })
}

EDIT 2 → ответ на отмену

Спасибо, Отмени. Ваш ответ имеет смысл для меня. Вот еще одна загадка. У меня есть класс, который является моим обработчиком API. Я хочу иметь возможность создать экземпляр этого класса и вызвать функцию на нем для получения данных из API. Я предпочел бы получить все данные с одним вызовом api, вместо того, чтобы делать отдельные вызовы каждый раз для каждого значения, которое мне нужно получить, поскольку один вызов API содержит все данные, которые мне нужны, но это может быть целый другой ответ. Вот код:

class GetInfoFromAPI {

    func getSpecificValue(index : String) -> String {
        /* I assume I need to send the values from this function, yea? but how do I get them here? */
    }

    func doThingsWithData( data: NSData ) -> String {
        /* code to extract string from NSData */
        var error: NSError?
        let jsonDict = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &error) as NSDictionary

        specificValue1 : String = jsonDict.valueForKey("value1") as String
        specificValue2 : String = jsonDict.valueForKey("value2") as String
        specificValue3 : String = jsonDict.valueForKey("value3") as String

        /* I want to get these ^^^ values into the ViewController below */
    }

    func getAsynchData() {
        let url:NSURL = NSURL(string:"some url")
        let request:NSURLRequest = NSURLRequest(URL:url)
        let queue:NSOperationQueue = NSOperationQueue()

        NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
            /* this next line gives the below error */
            doThingsWithData(data)
        })
    }
}


class ViewController: UIViewController {

    @IBOutlet var labelVariable1: UILabel
    @IBOutlet var labelVariable2: UILabel
    @IBOutlet var labelVariable3: UILabel

    let apiInstance = GetInfoFromAPI()

    @IBAction func buttonTapped(sender : AnyObject) {
        labelVariable1 = apiInstance.getSpecificValue(1)
        labelVariable2 = apiInstance.getSpecificValue(2)
        labelVariable3 = apiInstance.getSpecificValue(3)
    }

}

Спасибо, что нашли время, чтобы ответить на мои вопросы. Я новичок в быстром, и переполнение стека чрезвычайно полезно!

4b9b3361

Ответ 1

Позвольте мне попытаться объяснить это - это непонимание резьбы, с которой я сам боролся сначала. Я попытаюсь немного упростить ситуацию. Когда вы запустите этот код:

NSLog("Log 1")

NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
        NSLog("Log in Completion Block")
})

NSLog("Log after request")

Вы получите результат, который выглядит следующим образом:

Log 1
Log after request
Log in completion block

Позвольте мне составить график, вид временной шкалы:

                    "Log 1" (before request is sent)
                                       |
                                       |
                           Request sent over Internet
                                       |
                                     /   \  
                   "Log after request"   |
               This is logged *before*   | 
           the other one, because this   |
          one doesn't have to wait for   |
               the network to respond.   |
                                         |
The method finishes and returns a value. |
------------------------------------------------------------------------------
                                         | The network finally responds,
                                         | and the completion block is run.
                                         |

                                         "Log in completion block"

Вертикальная линия - это то, где метод заканчивается и возвращается. Во всех случаях ваш метод уже вернул значение своему вызывающему абоненту до запуска блока завершения. Вы не можете думать об этом линейно.

Я должен выполнять всю работу с этим запросом в этом блоке и не извлекать данные?

Да, по существу. Я могу помочь больше, если вы покажете мне код, который называет getAsynchData() в первую очередь.