получить пустой массив при вызове получения данных синтаксического анализа - swift [duplicate]

Python 3.6.0 Timings

Вот результаты синхронизации с использованием Python 3.6.0. Имейте в виду, что эти времена относятся друг к другу, а не абсолютны.

Я придерживался только мелких копий, а также добавил некоторые новые методы, которые не были возможны в Python2, например list.copy() ( Python3 эквивалент среза ) и распаковки (*new_list, = list):

METHOD                  TIME TAKEN
b = a[:]                6.468942025996512   #Python2 winner
b = a.copy()            6.986593422974693   #Python3 "slice equivalent"
b = []; b.extend(a)     7.309216841997113
b = a[0:len(a)]         10.916740721993847
*b, = a                 11.046738261007704
b = list(a)             11.761539687984623
b = [i for i in a]      24.66165203397395
b = copy.copy(a)        30.853400873980718
b = []
for item in a:
  b.append(item)        48.19176080400939

Мы видим, что старый победитель по-прежнему выходит сверху, но на самом деле не на огромную сумму, учитывая повышенную читаемость подхода Python3 list.copy().

Обратите внимание, что эти методы делают not выводными эквивалентными результатами для любого ввода, отличного от списков. Все они работают для разрезаемых объектов, некоторые работы для любого итерабельного, но только copy.copy() работает для любого объекта Python.


Вот код тестирования для заинтересованных сторон ( Шаблон отсюда ):

import timeit

COUNT = 50000000
print("Array duplicating. Tests run", COUNT, "times")
setup = 'a = [0,1,2,3,4,5,6,7,8,9]; import copy'

print("b = list(a)\t\t", timeit.timeit(stmt='b = list(a)', setup=setup, number=COUNT))
print("b = copy.copy(a)\t\t", timeit.timeit(stmt='b = copy.copy(a)', setup=setup, number=COUNT))
print("b = a.copy()\t\t", timeit.timeit(stmt='b = a.copy()', setup=setup, number=COUNT))
print("b = a[:]\t\t", timeit.timeit(stmt='b = a[:]', setup=setup, number=COUNT))
print("b = a[0:len(a)]\t", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
print("*b, = a\t", timeit.timeit(stmt='*b, = a', setup=setup, number=COUNT))
print("b = []; b.extend(a)\t", timeit.timeit(stmt='b = []; b.extend(a)', setup=setup, number=COUNT))
print("b = []\nfor item in a: b.append(item)\t", timeit.timeit(stmt='b = []\nfor item in a:  b.append(item)', setup=setup, number=COUNT))
print("b = [i for i in a]\t", timeit.timeit(stmt='b = [i for i in a]', setup=setup, number=COUNT))

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 21 August 2018 в 22:35
поделиться
  • 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 21 August 2018 в 22:35
поделиться
  • 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 21 August 2018 в 22:35
поделиться

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

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 21 August 2018 в 22:35
поделиться
  • 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 21 August 2018 в 22:35
поделиться

Свифт 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 21 August 2018 в 22:35
поделиться