В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.
При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.
Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».
Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this
. Возьмем этот пример:
public class Some {
private int id;
public int getId(){
return this.id;
}
public setId( int newId ) {
this.id = newId;
}
}
И в другом месте вашего кода:
Some reference = new Some(); // Point to a new object of type Some()
Some otherReference = null; // Initiallly this points to NULL
reference.setId( 1 ); // Execute setId method, now private var id is 1
System.out.println( reference.getId() ); // Prints 1 to the console
otherReference = reference // Now they both point to the only object.
reference = null; // "reference" now point to null.
// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );
// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...
Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference
и otherReference
оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.
Вы можете передать обратный вызов и вызвать обратный вызов внутри асинхронного вызова
примерно так:
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)")
}
}
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
.
Future
. Но посмотрите на github.com/mxcl/PromiseKit , он отлично работает с Swiftz!
– badeleux
28 July 2015 в 08:45
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()
Другой пример:
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)
}
}
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
}
Свифт 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()
}
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