Необходимо настроить NSJSONSerialization на iOS10

63
6

После обновления до iOS10 пользователи начали жаловаться на аварии моего приложения. Я тестирую его с помощью iOS10 на симуляторе, и, действительно, приложение выходит из строя с сообщением "Невозможно передать значение типа" __NSArrayI "в" NSMutableArray ". Здесь мой код, пожалуйста, помогите:

import Foundation

protocol getAllListsModel: class {
func listsDownloadingComplete(downloadedLists: [ContactsList])
}

class ListsDownloader: NSObject, NSURLSessionDataDelegate{

//properties

weak var delegate: getAllListsModel!

var data : NSMutableData = NSMutableData()

func downloadLists() {

let urlPath: String = "http://..."
let url: NSURL = NSURL(string: urlPath)!
var session: NSURLSession!
let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration() //defaultSessionConfiguration()

session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)

let task = session.dataTaskWithURL(url)

task.resume()

}

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
self.data.appendData(data);
}

func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error != nil {
print("Failed to download data")
}else {
self.parseJSON()
print("Lists downloaded")
}

}
func parseJSON() {

var jsonResult: NSMutableArray = NSMutableArray()

do{
try jsonResult = NSJSONSerialization.JSONObjectWithData(self.data, options:NSJSONReadingOptions.AllowFragments) as! NSMutableArray

} catch let error as NSError {
print(error)
}

var jsonElement: NSDictionary = NSDictionary()
var downloadedLists: [ContactsList] = []

for i in 0...jsonResult.count-1 {

jsonElement = jsonResult[i] as! NSDictionary

let tempContactsList = ContactsList()

//the following insures none of the JsonElement values are nil through optional binding
let id = jsonElement["id"] as? String
let name = jsonElement["name"] as? String
let pin = jsonElement["pin"] as? String
let lastUpdated = jsonElement["created"] as? String
let listAdminDeviceID = jsonElement["admin"] as? String

tempContactsList.id = id
tempContactsList.name = name
tempContactsList.pin = pin
tempContactsList.lastUpdated = lastUpdated
tempContactsList.listAdmin = listAdminDeviceID

downloadedLists.append(tempContactsList)

}

dispatch_async(dispatch_get_main_queue(), { () -> Void in

self.delegate.listsDownloadingComplete(downloadedLists)

})
}
}

спросил(а) 2021-01-25T20:31:03+03:00 4 месяца, 4 недели назад
1
Решение
77

Даже в iOS 9 не было гарантии NSJSONSerialization.JSONObjectWithData(_:options:) возвращал изменяемый объект или нет. Вы должны были указать NSJSONReadingOptions.MutableContainers.

И в вашем коде вы не jsonResult, а это значит, что вам не нужно объявлять его как NSMutableArray. Просто замените NSMutableArray на NSArray, и тогда вам не нужно указывать NSJSONReadingOptions.MutableContainers.

Но, как предполагает вадиан, вам лучше использовать типы Swift, а не NSArray или NSDictionary. Этот код должен работать как в iOS 9, так и в 10.

func parseJSON() {

var jsonResult: [[String: AnyObject]] = [] //<- use Swift type

do{
try jsonResult = NSJSONSerialization.JSONObjectWithData(self.data, options: []) as! [[String: AnyObject]] //<- convert to Swift type, no need to specify options

} catch let error as NSError {
print(error)
}

var downloadedLists: [ContactsList] = []

for jsonElement in jsonResult { //<- your for-in usage can be simplified

let tempContactsList = ContactsList()

//the following insures none of the JsonElement values are nil through optional binding
let id = jsonElement["id"] as? String
let name = jsonElement["name"] as? String
let pin = jsonElement["pin"] as? String
let lastUpdated = jsonElement["created"] as? String
let listAdminDeviceID = jsonElement["admin"] as? String

tempContactsList.id = id
tempContactsList.name = name
tempContactsList.pin = pin
tempContactsList.lastUpdated = lastUpdated
tempContactsList.listAdmin = listAdminDeviceID

downloadedLists.append(tempContactsList)

}

dispatch_async(dispatch_get_main_queue(), { () -> Void in

self.delegate.listsDownloadingComplete(downloadedLists)

})
}

Попробуйте это и проверьте его на устройствах iOS 10.

(Преобразование as! Будет приводить к некоторым странным сбоям, когда ваш сервер работает неправильно, но это будет другой проблемой, поэтому я сохраню его там.)

ответил(а) 2021-01-25T20:31:03+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема