Exception thrown if no data are received - ios

I am using following Class to receive data from an external database:
import Foundation
protocol HomeModelProtocal: class {
func itemsDownloaded(items: NSArray)
}
class HomeModel: NSObject, NSURLSessionDataDelegate {
//properties
weak var delegate: HomeModelProtocal!
var data : NSMutableData = NSMutableData()
var mi_movil: String = ""
let misDatos:NSUserDefaults = NSUserDefaults.standardUserDefaults()
var urlPath: String = "http:...hidden here.."
let parametros = "?id="
func downloadItems() {
mi_movil = misDatos.stringForKey("ID_IPHONE")!
print ("mi_movil en HOMEMODEL:",mi_movil)
urlPath = urlPath + parametros + mi_movil
let url: NSURL = NSURL(string: urlPath)!
var session: NSURLSession!
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
print ("LA URL ES: ",url)
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 {
print("Data downloaded")
self.parseJSON()
}
}
func parseJSON() {
var jsonResult: NSMutableArray = NSMutableArray()
do{
jsonResult = try NSJSONSerialization.JSONObjectWithData(self.data, options:NSJSONReadingOptions.AllowFragments) as! NSMutableArray
} catch let error as NSError {
print(error)
}
var jsonElement: NSDictionary = NSDictionary()
let locations: NSMutableArray = NSMutableArray()
for(var i = 0; i < jsonResult.count; i++)
{
jsonElement = jsonResult[i] as! NSDictionary
print (jsonElement)
let location = MiAutoModel()
//the following insures none of the JsonElement values are nil through optional binding
if let id_mis_autos = jsonElement["id_mis_autos"] as? String,
let modelo = jsonElement["modelo"] as? String,
let ano = jsonElement["ano"] as? String,
let id_movil = jsonElement["id_movil"] as? String
{
location.id_mis_autos = id_mis_autos
location.modelo = modelo
location.ano = ano
location.id_movil = id_movil
}
locations.addObject(location)
}
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.delegate.itemsDownloaded(locations)
})
}
}
If there are received data, it works fine but if there are no data an exception is thrown:
Could not cast value of type '__NSArray0' (0x1a0dd2978) to 'NSMutableArray' (0x1a0dd3490)
What should I change to detect if there are no data to avoid the exception?

Since you don't seem to be modifying jsonResult anywhere, the obvious choice is to make it an NSArray instead of an NSMutableArray, and change the downcasting to match that.

I'm not sure why you're using NSDictionary and NSMutableArray but this is how I would do it:
for result in jsonResult {
guard let jsonElement = result as? [String:AnyObject] else { return }
let locations: [MiAutoModel] = []
let location = MiAutoModel()
//the following insures none of the JsonElement values are nil through optional binding
let id_mis_autos = jsonElement["id_mis_autos"] as? String ?? ""
let modelo = jsonElement["modelo"] as? String ?? ""
let ano = jsonElement["ano"] as? String ?? ""
let id_movil = jsonElement["id_movil"] as? String ?? ""
location.id_mis_autos = id_mis_autos
location.modelo = modelo
location.ano = ano
location.id_movil = id_movil
locations.append(location)
}
You might have to change some of the code depending on your situation.

Related

Showing multiple location using 'MKMapView'

I am trying to show multiple locations which saved in Mysql using the code below. The data is loading but I have no idea how to show multiple locations depending on latitude and longitude.
Mysql is connected to application via PHP file.
Here is my code, the part which I called from NSObject:
func downloadItems() {
// the download function
// return the nsuserdefaults which hold the lati and longi from the notification table
UserDefaults.standard.string(forKey: "test");
let myUrl = UserDefaults.standard.string(forKey: "test");
let urlPath: String = myUrl!
let url: URL = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON(data!)
}
}
task.resume()
}
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let locations = NSMutableArray()
for i in 0 ..< jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let location = LocationModel()
//the following insures none of the JsonElement values are nil through optional binding
if let evIdL = jsonElement["id"] as? String,
let evUserNameL = jsonElement["username"] as? String,
let evNotikindL = jsonElement["notikind"] as? String,
let evLatiL = jsonElement["lati"] as? String,
let evLongiL = jsonElement["longi"] as? String,
let evLocatL = jsonElement["locat"] as? String,
let evTimedateL = jsonElement["timedate"] as? String,
let evDistanceL = jsonElement["distance"] as? String
{
location.evId = evIdL
location.evUsername = evUserNameL
location.evNotikind = evNotikindL
location.evLati = evLatiL
location.evLongi = evLongiL
location.evLocat = evDistanceL
location.evTimedate = evTimedateL
location.evDisatnce = evDistanceL
location.evLocat = evLocatL
}
locations.add(location)
}
DispatchQueue.main.async(execute: { () -> Void in
self.delegate.itemsDownloaded(items: locations)
})
}
}
I have no idea how to show few location on map.
try this code....
var locations = NSMutableArray()
var mapView = GMSMapView()
for i in 0..< location.count{
let obj = location[i]
lat = obj["lati"] as? Double
lng = obj["longi"] as? Double
let markerPoint = GMSMarker()
markerPoint.position = CLLocationCoordinate2D(latitude: lat!, longitude: lng!)
markerPoint.iconView = self.avtarImage() // Your image name
markerPoint.map = mapView // your mapview object name
markerPoint.zIndex = Int32(i)
markerPoint.infoWindowAnchor = CGPoint(x: 0, y: 0)
markerPoint.accessibilityLabel = String(format: "%d", i)
}

Swift - Load/save from CoreData generates duplicate entries

I have run into a problem where I can save and load into and from CoreData in Swift for my iOS app, but I run into a problem where I have tried to guard for duplicate entries, but it does not seem to work. can anyone tell me where I went wrong? Thanks!
My ViewController class:
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDelegate,
UITableViewDataSource {
#IBOutlet weak var headerLabel:UILabel!
#IBOutlet weak var myTableView: UITableView!
var lenders = [LenderData]()
var lendersTemp = [LenderData]()
override func viewDidLoad() {
super.viewDidLoad()
self.myTableView.rowHeight = 90
myTableView.delegate = self
myTableView.dataSource = self
let fetchRequest: NSFetchRequest<LenderData> = LenderData.fetchRequest()
do {
let lenders = try PersistenceService.context.fetch(fetchRequest)
self.lenders = lenders
} catch {
// Who cares....
}
downloadJSON {
for tempLender in self.lendersTemp {
if !self.lenders.contains(where: {$0.id == tempLender.id}) {
self.lenders.append(tempLender)
}
}
self.lendersTemp.removeAll()
PersistenceService.saveContext()
self.myTableView.reloadData()
}
}
func downloadJSON(completed: #escaping () -> ()) {
let url = URL(string: "https://api.kivaws.org/v1/loans/newest.json")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print("JSON not downloaded")
} else {
if let content = data {
do {
let myJSONData = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
var imageID:Int64 = -1
var country:String = "N/A"
var latLongPair:String = "0.000000 0.000000"
var town:String = "N/A"
if let loans = myJSONData["loans"] as? NSArray {
for i in 0...loans.count-1 {
if let lender = loans[i] as? NSDictionary {
if let imageData = lender["image"] as? NSDictionary { imageID = imageData["id"] as! Int64 }
if let countryData = lender["location"] as? NSDictionary {
country = countryData["country"] as! String
town = countryData["town"] as! String
if let geo = countryData["geo"] as? NSDictionary {
latLongPair = geo["pairs"] as! String
}
}
let newLender = LenderData(context: PersistenceService.context)
newLender.id = lender["id"] as! Int64
newLender.name = lender["name"] as? String
newLender.image_id = imageID
newLender.activity = lender["activity"] as? String
newLender.use = lender["use"] as? String
newLender.loan_amount = lender["loan_amount"] as! Int32
newLender.funded_amount = lender["funded_amount"] as! Int32
newLender.country = country
newLender.town = town
newLender.geo_pairs = latLongPair
self.lendersTemp.append(newLender)
}
}
}
DispatchQueue.main.async {
completed()
}
} catch {
print("Error occured \(error)")
}
}
}
}
task.resume()
}
}
EDIT
Added the part of the code where I populate the lendersTemp array
I quote matt on this one from the comments:
So... You are appending to self.lendersTemp on a background thread but reading it on the main thread. Instead, get rid of it and just pass the data right thru the completed function.
Which is exactly what I did. And this worked

How can I do an HTTP Post before reading the JSON?

I am reading JSON from a URL and that has been working correctly. This is my code:
#IBOutlet weak var ProfilesCell: UITableView!
let cellspacing: CGFloat = 50
var names = [String]()
var posts = [String]()
var locations = [String]()
var votes = [String]()
var comments = [String]()
override func viewDidLoad() {
super.viewDidLoad()
ProfilesCell.dataSource = self
let url:URL = URL(string: "http://"+Connection_String+":8000/profile_view")!
URLSession.shared.dataTask(with:url, completionHandler: {(data, response, error) in
if error != nil {
print(error)
} else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String:Any]
if let Profile = parsedData["Profile"] as! [AnyObject]?
{
for Stream in Profile {
if let fullname = Stream["fullname"] as? String {
self.names.append(fullname)
}
if let post = Stream["post"] as? String {
self.posts.append(post)
}
if let location = Stream["location"] as? String {
self.locations.append(location)
}
if let vote = Stream["votes"] as? String {
self.votes.append(vote.appending(" Votes"))
}
if let comment = Stream["comments"] as? String {
self.comments.append(comment.appending(" Comments"))
}
DispatchQueue.main.async {
self.ProfilesCell.reloadData()
}
}
}
} catch let error as NSError {
print(error)
}
}
}).resume()
}
That code above correctly parses the JSON and the data is returned to the TableView. I now want to do an HTTP Post before reading that JSON and the parameter name is profile_id and I know that is something wrong in my code because if I do an HTML form with the parameter, things work correctly.
This is the new code that I now have:
#IBOutlet weak var ProfilesCell: UITableView!
let cellspacing: CGFloat = 50
var names = [String]()
var posts = [String]()
var locations = [String]()
var votes = [String]()
var comments = [String]()
override func viewDidLoad() {
super.viewDidLoad()
ProfilesCell.dataSource = self
let url:URL = URL(string: "http://"+Connection_String+":8000/profile_view")!
let ss = "32"
var request = URLRequest(url:url)
let paramString = "profile_id=\(ss)"
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
request.httpBody = paramString.data(using: .utf8)
URLSession.shared.dataTask(with:url, completionHandler: {(data, response, error) in
if error != nil {
print(error)
} else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String:Any]
if let Profile = parsedData["Profile"] as! [AnyObject]?
{
for Stream in Profile {
if let fullname = Stream["fullname"] as? String {
self.names.append(fullname)
}
if let post = Stream["post"] as? String {
self.posts.append(post)
}
if let location = Stream["location"] as? String {
self.locations.append(location)
}
if let vote = Stream["votes"] as? String {
self.votes.append(vote.appending(" Votes"))
}
if let comment = Stream["comments"] as? String {
self.comments.append(comment.appending(" Comments"))
}
DispatchQueue.main.async {
self.ProfilesCell.reloadData()
}
}
}
} catch let error as NSError {
print(error)
}
}
}).resume()
}
Now with this extra code the URL is still being hit but profile_id is showing null even though I have hardcoded the number 32. I also get this message displayed:
Error Domain=NSCocoaErrorDomain Code=3840 "No value." UserInfo={NSDebugDescription=No value.}

NSURLSession.sharedSession().dataTaskWithRequest runs slow in function

My problem arises when I want to populate data from my mysql database into a class object. I am trying to return an array of objects and it returns nil and then it fills itself somehow. How can I make it fill before returning the blank array?
Here is my code and a screenshot of code output
import Foundation
class Research
{
var mainResearchImageURL:String = ""
var userProfileImageURL:String = ""
var caption:String = ""
var shortDescription:String = ""
init(mainResearchImageURL :String, userProfileImageURL:String, caption:String, shortDescription:String)
{
self.mainResearchImageURL = mainResearchImageURL
self.userProfileImageURL = userProfileImageURL
self.caption = caption
self.shortDescription = shortDescription
}
class func downloadAllResearches()->[Research]
{
var researches = [Research]()
let urlString = "http://localhost/test/index.php"
let request = NSMutableURLRequest(URL: NSURL(string: urlString)!)
request.HTTPMethod = "POST"
let postString = "action=listresearches"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error in
if (error == nil) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSArray
//let dictionary = json!.firstObject as? NSDictionary
var counter:Int = 0;
for line in json!{
let researchData = line as! NSDictionary
let researchLineFromData = Research(mainResearchImageURL: researchData["research_mainImageURL"] as! String, userProfileImageURL: researchData["research_creatorProfileImageURL"] as! String, caption: researchData["research_caption"] as! String, shortDescription: researchData["research_shortDescription"] as! String)
researches.append(researchLineFromData) //researches bir dizi ve elemanları Research türünde bir sınıftan oluşuyor.
counter += 1
print ("counter value \(counter)")
print("array count in loop is = \(researches.count)")
}
}catch let error as NSError{
print(error)
}
} else {
print(error)
}})
task.resume()
print("array count in return is = \(researches.count)")
return researches
}
}
And this is the output:
add this on you completionHandler ( it works if you update a view)
dispatch_async(dispatch_get_main_queue(), {
if (error == nil) { ...... }
})
Advice 1:
return the task and use a completion param in your method,
you can cancel the task if it's too slow.
Advice 2 :
Use alamofire and swiftyJson framework
What happen here is that you are returning the value before finish (remember that the call is Asynchronous), you can make something like this:
class func downloadAllResearches(success:([Research])->Void,failure:(String)->Void)
{
var researches = [Research]()
let urlString = "http://localhost/test/index.php"
let request = NSMutableURLRequest(URL: NSURL(string: urlString)!)
request.HTTPMethod = "POST"
let postString = "action=listresearches"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error in
if (error == nil) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSArray
//let dictionary = json!.firstObject as? NSDictionary
var counter:Int = 0;
for line in json!{
let researchData = line as! NSDictionary
let researchLineFromData = Research(mainResearchImageURL: researchData["research_mainImageURL"] as! String, userProfileImageURL: researchData["research_creatorProfileImageURL"] as! String, caption: researchData["research_caption"] as! String, shortDescription: researchData["research_shortDescription"] as! String)
researches.append(researchLineFromData) //researches bir dizi ve elemanları Research türünde bir sınıftan oluşuyor.
counter += 1
print ("counter value \(counter)")
print("array count in loop is = \(researches.count)")
}
success(researches)
}catch let error as NSError{
print(error)
failure("Can be extract from NSERROR")
}
} else {
print(error)
failure("Error - Can be extract for NSERROR")
}})
task.resume()
}
And for call this Fuction use something like this:
Research.downloadAllResearches({ (objects:[Research]) -> Void in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
//Do whatever you like with the content
})
}) { (failureLiteral:String) -> Void in
}

NSURLSession didCompleteWithError: how to determine what task it is?

I have a class that conform to the NSURLSession delegates for downloading data and have an issue when more than one service is called when finished they call the method func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?), the results are parsed and handled here to be returned to the correct view controller.
How do I know from what session or task the results are so I can call the correct view controller?
import Foundation
class Support{
// MARK - Properties
var ID: Int!
var SoftekID: String!
var Subject: String!
var LastUpdate: String!
var LastUpdatedBy: String!
var Priority: Int!
var Impact: Int!
var SupportType: String!
var Importance: Int!
// MARK: General
init() {
self.ID = 0
self.SoftekID = ""
self.Subject = ""
self.LastUpdate = ""
self.LastUpdatedBy = ""
self.Priority = 0
self.Impact = 0
self.SupportType = ""
self.Importance = 0
}
func getSupportTickets(){
let sp = SuppportProvider()
sp.getSupportTickets()
}
}
class SuppportProvider: NSObject, NSURLSessionDelegate, NSURLSessionDataDelegate, NSURLSessionTaskDelegate{
// MARK: - Properties
var mData: NSMutableData?
var session: NSURLSession!
override init(){
super.init()
prepareConnection()
}
// MARK: - Methods
func prepareConnection(){
session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: self, delegateQueue:nil)
}
func getSupportTickets(){
var request = NSMutableURLRequest(URL: NSURL(string: "http://10.0.58.137/ISOWeb.UI/api/CSMobile/GetSupportTickets?PageNumber=0&PagingSize=10&TicketStatus=Priority")!,
cachePolicy: NSURLRequestCachePolicy.UseProtocolCachePolicy,
timeoutInterval: 20.0)
let task = session.dataTaskWithRequest(request)
mData = NSMutableData()
task.resume()
}
func getHelpInformation(){
var request = NSMutableURLRequest(URL: NSURL(string: "http://10.0.58.137/ISOWeb.UI/api/CSMobile/GetHelpInformation")!,
cachePolicy: NSURLRequestCachePolicy.UseProtocolCachePolicy,
timeoutInterval: 20.0)
let task = session.dataTaskWithRequest(request)
mData = NSMutableData()
task.resume()
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
mData!.length = 0
completionHandler(NSURLSessionResponseDisposition.Allow)
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
mData!.appendData(data)
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error != nil{
println("An error has occured completing the request")
}else{
//Result for method: getSupportTickets
var value = NSString(bytes: mData!.mutableBytes, length: mData!.length, encoding: NSUTF8StringEncoding)
var jError: NSError?
if let JSONResult: Array<NSDictionary> = NSJSONSerialization.JSONObjectWithData(mData!, options: NSJSONReadingOptions.AllowFragments, error: &jError) as? Array<NSDictionary> {
if JSONResult.count > 0 {
var arr = Array<Support>()
for dict in JSONResult{
let item = Support()
if (dict["ID"] as? Int != nil) {
item.ID = dict["ID"] as! Int
}else {
item.ID = 0
}
if (dict["SoftekID"] as? String != nil) {
item.SoftekID = dict["SoftekID"] as! String
}else {
item.SoftekID = ""
}
if (dict["Subject"] as? String != nil) {
item.Subject = dict["Subject"] as! String
}else {
item.Subject = ""
}
if (dict["LastUpdate"] as? String != nil) {
item.LastUpdate = dict["LastUpdate"] as! String
}else {
item.LastUpdate = ""
}
if (dict["LastUpdatedBy"] as? String != nil) {
item.LastUpdatedBy = dict["LastUpdatedBy"] as! String
}else {
item.LastUpdatedBy = ""
}
if (dict["Priority"] as? Int != nil) {
item.Priority = dict["Priority"] as! Int
}else {
item.Priority = 0
}
if (dict["Impact"] as? Int != nil) {
item.Impact = dict["Impact"] as! Int
}else {
item.Impact = 0
}
if (dict["SupportType"] as? String != nil) {
item.SupportType = dict["SupportType"] as! String
}else {
item.SupportType = ""
}
if (dict["Importance"] as? Int != nil) {
item.Importance = dict["Importance"] as! Int
}else {
item.Importance = 0
}
arr.append(item)
}
}
}
//Result for method: getHelpInformation
//How to know to which task holds the result?
}
}
}
UPDATE
import Foundation
class CSSupport{
// MARK - Properties
var ID: Int!
var SoftekID: String!
var Subject: String!
var LastUpdate: String!
var LastUpdatedBy: String!
var Priority: Int!
var Impact: Int!
var SupportType: String!
var Importance: Int!
// MARK: General
init() {
self.ID = 0
self.SoftekID = ""
self.Subject = ""
self.LastUpdate = ""
self.LastUpdatedBy = ""
self.Priority = 0
self.Impact = 0
self.SupportType = ""
self.Importance = 0
}
}
class Support:NSObject, NSURLSessionDelegate, NSURLSessionDataDelegate, NSURLSessionTaskDelegate{
// MARK: - Properties
var mData: NSMutableData?
var session: NSURLSession!
override init(){
super.init()
var configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
session = NSURLSession(configuration:configuration, delegate: self, delegateQueue:nil)
}
// MARK: - Methods
func getSupportTickets(){
var request = NSMutableURLRequest(URL: NSURL(string: "http://10.0.58.137/ISOWeb.UI/api/CSMobile/GetSupportTickets?PageNumber=0&PagingSize=10&TicketStatus=Priority")!,
cachePolicy: NSURLRequestCachePolicy.UseProtocolCachePolicy,
timeoutInterval: 20.0)
let task = session.dataTaskWithRequest(request)
mData = NSMutableData()
task.resume()
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
mData!.length = 0
completionHandler(NSURLSessionResponseDisposition.Allow)
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
mData!.appendData(data)
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error != nil{
println("An error has occured completing the request")
}else{
var value = NSString(bytes: mData!.mutableBytes, length: mData!.length, encoding: NSUTF8StringEncoding)
var jError: NSError?
switch task.taskIdentifier {
case 1:
if let JSONResult: Array<NSDictionary> = NSJSONSerialization.JSONObjectWithData(mData!, options: NSJSONReadingOptions.AllowFragments, error: &jError) as? Array<NSDictionary> {
if JSONResult.count > 0 {
var arr = Array<CSSupport>()
for dict in JSONResult{
let item = CSSupport()
if (dict["ID"] as? Int != nil) {
item.ID = dict["ID"] as! Int
}else {
item.ID = 0
}
if (dict["SoftekID"] as? String != nil) {
item.SoftekID = dict["SoftekID"] as! String
}else {
item.SoftekID = ""
}
if (dict["Subject"] as? String != nil) {
item.Subject = dict["Subject"] as! String
}else {
item.Subject = ""
}
if (dict["LastUpdate"] as? String != nil) {
item.LastUpdate = dict["LastUpdate"] as! String
}else {
item.LastUpdate = ""
}
if (dict["LastUpdatedBy"] as? String != nil) {
item.LastUpdatedBy = dict["LastUpdatedBy"] as! String
}else {
item.LastUpdatedBy = ""
}
if (dict["Priority"] as? Int != nil) {
item.Priority = dict["Priority"] as! Int
}else {
item.Priority = 0
}
if (dict["Impact"] as? Int != nil) {
item.Impact = dict["Impact"] as! Int
}else {
item.Impact = 0
}
if (dict["SupportType"] as? String != nil) {
item.SupportType = dict["SupportType"] as! String
}else {
item.SupportType = ""
}
if (dict["Importance"] as? Int != nil) {
item.Importance = dict["Importance"] as! Int
}else {
item.Importance = 0
}
arr.append(item)
}
}
}
break
case 2:
break
default:
println("No task was found.")
break
}
}
}
}
Yes, the lack of any sort of customizable storage is kind of annoying, particularly because the identifier is only unique on a per-session basis. There are a few ways to handle this:
If you're using background sessions or a mixture of foreground and background sesions, I think the best thing you can do is a two-level lookup, in which you associate a mutable dictionary with each session and look up the session first, then look up the task by its identifier within the per-session dictionary:
For background sessions, provide an identifier to use as the key in the top-level mutable dictionary.
For other sessions, use the session object itself as the key in the top-level mutable dictionary.
If you're using only foreground tasks (not in a background session, that is), you should be able to just use the tasks as dictionary keys and look up additional data related to the tasks.
I think that both of those techniques should work correctly. You might also be able to use associated objects on the task to store additional data (so long as you aren't working with background sessions).
One thing you definitely can't do (I already filed a bug about this) is subclass NSURLRequest and store additional data there, because NSURLSession returns its own copy of the NSURLRequest (rather than your custom subclass) when you ask for currentRequest, and returns a seemingly random instance of your subclass (unrelated to the actual original request) when you ask for orginalRequest.
It's amazing how much effort everyone has to expend creating external dictionaries to work around the lack of a simple refCon object property on each task and on each session. It is definitely worth filing a bug to ask for that feature.
Why not using your own custom string identifier in taskDescription which is a member of NSURLSessionTask ?
Maybe taskIdentifier property could help you: https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSessionTask_class/index.html#//apple_ref/occ/instp/NSURLSessionTask/taskIdentifier

Resources