Swift4: возвращает HTTP-ответ от функции [duplicate]

Когда вы объявляете ссылочную переменную (т. е. объект), вы действительно создаете указатель на объект. Рассмотрим следующий код, в котором вы объявляете переменную примитивного типа int:

int x;
x = 10;

В этом примере переменная x является int, и Java инициализирует ее для 0. Когда вы назначаете его 10 во второй строке, ваше значение 10 записывается в ячейку памяти, на которую указывает x.

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

Integer num;
num = new Integer(10);

Первая строка объявляет переменную с именем num, но она не содержит примитивного значения. Вместо этого он содержит указатель (потому что тип Integer является ссылочным типом). Поскольку вы еще не указали, что указать на Java, он устанавливает значение null, что означает «Я ничего не указываю».

Во второй строке ключевое слово new используется для создания экземпляра (или создания ) объекту типа Integer и переменной указателя num присваивается этот объект. Теперь вы можете ссылаться на объект, используя оператор разыменования . (точка).

Exception, о котором вы просили, возникает, когда вы объявляете переменную, но не создавали объект. Если вы попытаетесь разыменовать num. Перед созданием объекта вы получите NullPointerException. В самых тривиальных случаях компилятор поймает проблему и сообщит вам, что «num не может быть инициализирован», но иногда вы пишете код, который непосредственно не создает объект.

Например, вы можете имеют следующий метод:

public void doSomething(SomeObject obj) {
   //do something to obj
}

В этом случае вы не создаете объект obj, скорее предполагая, что он был создан до вызова метода doSomething. К сожалению, этот метод можно вызвать следующим образом:

doSomething(null);

В этом случае obj имеет значение null. Если метод предназначен для того, чтобы что-то сделать для переданного объекта, целесообразно бросить NullPointerException, потому что это ошибка программиста, и программисту понадобится эта информация для целей отладки.

Альтернативно, там могут быть случаи, когда цель метода заключается не только в том, чтобы работать с переданным в объекте, и поэтому нулевой параметр может быть приемлемым. В этом случае вам нужно будет проверить нулевой параметр и вести себя по-другому. Вы также должны объяснить это в документации. Например, doSomething может быть записано как:

/**
  * @param obj An optional foo for ____. May be null, in which case 
  *  the result will be ____.
  */
public void doSomething(SomeObject obj) {
    if(obj != null) {
       //do something
    } else {
       //do something else
    }
}

Наконец, Как определить исключение & amp; причина использования Трассировки стека

51
задан Mark Tyers 8 August 2014 в 13:28
поделиться

6 ответов

Вы можете передать обратный вызов и вызвать обратный вызов внутри асинхронного вызова

примерно так:

class func getGenres(completionHandler: (genres: NSArray) -> ()) {
    ...
    let task = session.dataTaskWithURL(url) {
        data, response, error in
        ...
        resultsArray = results
        completionHandler(genres: resultsArray)
    }
    ...
    task.resume()
}

, а затем вызвать этот метод:

override func viewDidLoad() {
    Bookshop.getGenres {
        genres in
        println("View Controller: \(genres)")     
    }
}
60
ответ дан Alexey Globchastyy 18 August 2018 в 09:09
поделиться
  • 1
    Спасибо за это. Мой последний вопрос: как я могу вызвать этот метод класса из моего контроллера представления. Код в настоящее время выглядит следующим образом: override func viewDidLoad() { super.viewDidLoad() var genres = Bookshop.getGenres() // Missing argument for parameter #1 in call //var genres:NSArray //Bookshop.getGenres(genres) NSLog("View Controller: %@", genres) } – Mark Tyers 8 August 2014 в 13:56
  • 2
    добавил к моему ответу – Alexey Globchastyy 8 August 2014 в 14:00
  • 3
    Спасибо огромное! Вы не поверите, сколько времени я потратил на этот вопрос, прежде чем я нашел ваш ответ! – The_Curry_Man 16 June 2016 в 00:34

Swiftz уже предлагает Future, который является основным строительным блоком Promise. Будущее - это обещание, которое не может потерпеть неудачу (все термины здесь основаны на интерпретации Scala, , где Promise является монадой ).

https: // github. com / maxpow4h / swiftz / blob / master / swiftz / Future.swift

Надеюсь, что в какой-то момент мы сможем написать его в полной версии в стиле Скала (я могу написать это сам в какой-то момент; Конечно, другие PR будут приветствоваться, это не так сложно, если будущее уже на месте).

В вашем конкретном случае я, вероятно, создаю Result<[Book]> (на основе версии Александроса Салазара Result [/ д2]). Тогда ваша сигнатура метода будет:

class func fetchGenres() -> Future<Result<[Book]>> {

Примечания

  • Я не рекомендую функции префикса с get в Swift. Это нарушит определенные виды совместимости с ObjC.
  • Я рекомендую развернуть весь путь до объекта Book, прежде чем возвращать результаты в качестве Future. Существует несколько способов, с помощью которых эта система может выйти из строя, и гораздо удобнее, если вы проверите все эти вещи, прежде чем обернуть их в Future. Переход к [Book] намного лучше для остальной части вашего кода Swift, чем передача NSArray.
10
ответ дан Community 18 August 2018 в 09:09
поделиться
  • 1
    Swiftz больше не поддерживает Future. Но посмотрите на github.com/mxcl/PromiseKit , он отлично работает с Swiftz! – badeleux 28 July 2015 в 08:45
  • 2
    взял меня на несколько секунд, чтобы понять, что вы не писали Swift и писали Swift z – Honey 18 August 2017 в 19:01
  • 3
    Это звучит как «Swiftz». является сторонней функциональной библиотекой для Swift. Поскольку ваш ответ, похоже, основан на этой библиотеке, вы должны указать это явно. (например, «Существует сторонняя библиотека под названием« Swiftz », которая поддерживает функциональные конструкции, такие как Futures, и должна служить хорошей отправной точкой, если вы хотите реализовать Promises.»). В противном случае ваши читатели просто удивятся, почему вы с ошибкой «Свифт». – Duncan C 2 January 2018 в 22:55
  • 4
    Обратите внимание, что github.com/maxpow4h/swiftz/blob/master/swiftz/Future.swift больше не работает. – Ahmad F 1 March 2018 в 08:16
self.urlSession.dataTask(with: request, completionHandler: { (data, response, error) in
            self.endNetworkActivity()

            var responseError: Error? = error
            // handle http response status
            if let httpResponse = response as? HTTPURLResponse {

                if httpResponse.statusCode > 299 , httpResponse.statusCode != 422  {
                    responseError = NSError.errorForHTTPStatus(httpResponse.statusCode)
                }
            }

            var apiResponse: Response
            if let _ = responseError {
                apiResponse = Response(request, response as? HTTPURLResponse, responseError!)
                self.logError(apiResponse.error!, request: request)

                // Handle if access token is invalid
                if let nsError: NSError = responseError as NSError? , nsError.code == 401 {
                    DispatchQueue.main.async {
                        apiResponse = Response(request, response as? HTTPURLResponse, data!)
                        let message = apiResponse.message()
                        // Unautorized access
                        // User logout
                        return
                    }
                }
                else if let nsError: NSError = responseError as NSError? , nsError.code == 503 {
                    DispatchQueue.main.async {
                        apiResponse = Response(request, response as? HTTPURLResponse, data!)
                        let message = apiResponse.message()
                        // Down time
                        // Server is currently down due to some maintenance
                        return
                    }
                }

            } else {
                apiResponse = Response(request, response as? HTTPURLResponse, data!)
                self.logResponse(data!, forRequest: request)
            }

            self.removeRequestedURL(request.url!)

            DispatchQueue.main.async(execute: { () -> Void in
                completionHandler(apiResponse)
            })
        }).resume()
0
ответ дан CrazyPro007 18 August 2018 в 09:09
поделиться

Другой пример:

class func getExchangeRate(#baseCurrency: String, foreignCurrency:String, completion: ((result:Double?) -> Void)!){
    let baseURL = kAPIEndPoint
    let query = String(baseCurrency)+"_"+String(foreignCurrency)

    var finalExchangeRate = 0.0
    if let url = NSURL(string: baseURL + query) {
        NSURLSession.sharedSession().dataTaskWithURL(url) { data, response, error in

            if ((data) != nil) {
                let jsonDictionary:NSDictionary = NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: nil) as NSDictionary

                if let results = jsonDictionary["results"] as? NSDictionary{
                    if let queryResults = results[query] as? NSDictionary{
                        if let exchangeRate = queryResults["val"] as? Double{
                            let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
                            dispatch_async(dispatch_get_global_queue(priority, 0)) {
                                dispatch_async(dispatch_get_main_queue()) {
                                    completion(result: exchangeRate)
                                }
                            }

                        }
                    }
                }
            }
            else {
                completion(result: nil)
            }

        }.resume()
    }
}    

Вызов:

 Currency.getExchangeRate(baseCurrency: "USD", foreignCurrency: "EUR") { (result) -> Void in
                if let exchangeValue = result {
                    print(exchangeValue)
                }
            }
8
ответ дан ericgu 18 August 2018 в 09:09
поделиться
  • 1
    Почему вы бы предложили очень конкретный пример обменного курса для вопроса о поиске в книге? Это только путает будущих людей, которые ищут ответ. – jbouaziz 6 November 2017 в 11:34
  • 2
    Потому что его концепция не имеет значения. Сосредоточьтесь на понимании не копирования и вставки – ericgu 4 February 2018 в 20:44
  • 3
    Если это так, то ваш пример слишком специфичен для простой концепции. – jbouaziz 11 February 2018 в 23:29

Swift 4.0

Для async Request-Response вы можете выполнить обработчик завершения пользователем. См. Ниже, я изменил ваше решение с помощью парадигмы обработки завершения.

func getGenres(_ completion: @escaping (NSArray) -> ()) {

        let urlPath = "http://creative.coventry.ac.uk/~bookshop/v1.1/index.php/genre/list"
        print(urlPath)

        guard let url = URL(string: urlPath) else { return }

        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            guard let data = data else { return }
            do {
                if let jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary {
                    let results = jsonResult["genres"] as! NSArray
                    print(results)
                    completion(results)
                }
            } catch {
                //Catch Error here...
            }
        }
        task.resume()
    }

Вы можете вызвать эту функцию, как показано ниже. Простой

getGenres { (array) in
    // Do operation with your array
}
1
ответ дан Jaydeep 18 August 2018 в 09:09
поделиться

Свифт 3 версии ответа @Alexey Globchastyy:

class func getGenres(completionHandler: @escaping (genres: NSArray) -> ()) {
...
let task = session.dataTask(with:url) {
    data, response, error in
    ...
    resultsArray = results
    completionHandler(genres: resultsArray)
}
...
task.resume()
}
3
ответ дан Nebojsa Nadj 18 August 2018 в 09:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: