Eu criei uma classe de utilitário em meu projeto Swift que lida com todas as solicitações e respostas REST. Eu construí uma API REST simples para poder testar meu código. Eu criei um método de classe que precisa retornar um NSArray, mas como a chamada da API é assíncrona, preciso retornar do método dentro da chamada assíncrona. O problema é que o async retorna void. Se eu estivesse fazendo isso no Node, usaria promessas de JS, mas não consigo descobrir uma solução que funcione no Swift.
import Foundation
class Bookshop {
class func getGenres() -> NSArray {
println("Hello inside getGenres")
let urlPath = "http://creative.coventry.ac.uk/~bookshop/v1.1/index.php/genre/list"
println(urlPath)
let url: NSURL = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
var resultsArray:NSArray!
let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
println("Task completed")
if(error) {
println(error.localizedDescription)
}
var err: NSError?
var options:NSJSONReadingOptions = NSJSONReadingOptions.MutableContainers
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: options, error: &err) as NSDictionary
if(err != nil) {
println("JSON Error \(err!.localizedDescription)")
}
//NSLog("jsonResults %@", jsonResult)
let results: NSArray = jsonResult["genres"] as NSArray
NSLog("jsonResults %@", results)
resultsArray = results
return resultsArray // error [anyObject] is not a subType of 'Void'
})
task.resume()
//return "Hello World!"
// I want to return the NSArray...
}
}
ios
rest
asynchronous
swift
Mark Tyers
fonte
fonte
Respostas:
Você pode passar callback e callback dentro da chamada assíncrona
algo como:
e chame este método:
fonte
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) }
Swiftz já oferece Futuro, que é o bloco de construção básico de uma promessa. Um futuro é uma promessa que não pode falhar (todos os termos aqui são baseados na interpretação de Scala, onde uma promessa é uma mônada ).
https://github.com/maxpow4h/swiftz/blob/master/swiftz/Future.swift
Espero que eventualmente se expanda para uma Promessa completa no estilo Scala (posso escrever sozinho em algum momento; tenho certeza de que outros PRs seriam bem-vindos; não é tão difícil com o Futuro já implementado).
No seu caso particular, eu provavelmente criaria um
Result<[Book]>
(baseado na versão de Alexandros Salazar deResult
). Então, a assinatura do seu método seria:Notas
get
em Swift. Isso quebrará certos tipos de interoperabilidade com ObjC.Book
objeto antes de retornar seus resultados como umFuture
. Esse sistema pode falhar de várias maneiras, e é muito mais conveniente verificar todas essas coisas antes de agrupá-las em umFuture
. Chegar[Book]
é muito melhor para o resto do código Swift do que entregar umNSArray
.fonte
Future
. Mas dê uma olhada em github.com/mxcl/PromiseKit , funciona muito bem com o Swiftz!get
prefixo indica retorno por referência em ObjC (como em-[UIColor getRed:green:blue:alpha:]
). Quando escrevi isso, fiquei preocupado que os importadores alavancassem esse fato (para retornar uma tupla automaticamente, por exemplo). Acontece que não. Quando escrevi isso, provavelmente também havia esquecido que KVC suporta prefixos "get" para acessadores (é algo que aprendi e esqueci várias vezes). Então concordou; Não encontrei nenhum caso em que o líderget
quebra as coisas. É apenas enganoso para aqueles que sabem o significado de ObjC "get".O padrão básico é usar o fechamento de manipuladores de conclusão.
Por exemplo, no próximo Swift 5, você usaria
Result
:E você o chamaria assim:
Observe, acima, estou despachando o manipulador de conclusão de volta para a fila principal para simplificar o modelo e as atualizações da IU. Alguns desenvolvedores se opõem a esta prática e usam qualquer fila
URLSession
usada ou usam sua própria fila (exigindo que o autor da chamada sincronize manualmente os resultados).Mas isso não é relevante aqui. O principal problema é o uso do manipulador de conclusão para especificar o bloco de código a ser executado quando a solicitação assíncrona for feita.
O mais antigo, o padrão Swift 4 é:
E você o chamaria assim:
Observe, acima, retirei o uso de
NSArray
(não usamos mais esses tipos de Objective-C em ponte ). Suponho que tínhamos umGenre
tipo e provavelmente o usamosJSONDecoder
, em vez deJSONSerialization
, para decodificá-lo. Mas essa pergunta não tinha informações suficientes sobre o JSON subjacente para entrar em detalhes aqui, então omiti isso para evitar obscurecer o problema principal, o uso de encerramentos como manipuladores de conclusão.fonte
Result
no Swift 4 e inferior, mas você mesmo deve declarar o enum. Estou usando esse tipo de padrão há anos.Swift 4.0
Para Solicitação-Resposta assíncrona, você pode usar o manipulador de conclusão. Veja abaixo, eu modifiquei a solução com paradigma de manipulação de conclusão.
Você pode chamar esta função conforme abaixo:
fonte
Versão Swift 3 da resposta de @Alexey Globchastyy:
fonte
Espero que você não esteja ainda preso nisso, mas a resposta curta é que você não pode fazer isso no Swift.
Uma abordagem alternativa seria retornar um retorno de chamada que fornecerá os dados de que você precisa assim que estiverem prontos.
fonte
callback
comclosure
s como você indicou oudelegation
como as APIs de cacau mais antigasExistem 3 maneiras de criar funções de retorno de chamada, a saber: 1. Manipulador de conclusão 2. Notificação 3. Delegados
Completion Handler Dentro do conjunto do bloco é executado e retornado quando a fonte estiver disponível, Handler irá esperar até que a resposta chegue para que a IU possa ser atualizada depois.
Notificação Um monte de informações é acionado em todo o aplicativo, o Listner pode recuperar e fazer uso dessas informações. Maneira assíncrona de obter informações ao longo do projeto.
Delegados O conjunto de métodos será acionado quando o delegado for chamado, a fonte deve ser fornecida pelos próprios métodos
fonte
fonte
Existem basicamente 3 maneiras de obter retorno de chamada rapidamente
Manipulador de fechamentos / conclusão
Delegados
Notificações
Os observadores também podem ser usados para serem notificados quando a tarefa assíncrona for concluída.
fonte
Existem alguns requisitos muito genéricos que gostariam que todo bom API Manager satisfizesse: implementará um API Client orientado a protocolo.
Interface inicial APIClient
Agora, verifique a estrutura API completa
fonte
Este é um pequeno caso de uso que pode ser útil: -
Ao chamar a função: -
fonte