I know this question was asked before, but answers were in Swift 3 and using older versions of Alamofire.
Problem: Can't figure out how to retrieve data from JSON response, mainly api_key.
Here is code for my response:
Alamofire.request(serverLink!, headers: headers).responseJSON{ response in
if response.value != nil {
//Some code to get api_key
print(response)
} else {
print("error")
}
When I print(response) I get the following:
SUCCESS: {
user = {
"api_key" = 9a13f31770b80767a57d753961acbd3a18eb1370;
"created_on" = "2010-09-30T12:57:42Z";
firstname = Paul;
id = 4;
"last_login_on" = "2018-03-27T10:15:10+03:00";
lastname = Smith;
login = admin;
mail = "admin#demo.com";
status = 1;
};
}
What I need to get is
"api_key" = 9a13f31770b80767a57d753961acbd3a18eb1370;
It could be in form of array, dict or just string containing:
9a13f31770b807...
Could someone please explain to me how to get(decode) it from this request?
EDIT
print(response.result.value):
RESPONSE: Optional({ user = { "api_key" = 9a13f31770b80767a57d753961acbd3a18eb1370; "created_on" = "2010-09-30T12:57:42Z"; firstname = Paul; id = 4; "last_login_on" = "2018-03-27T11:10:25+03:00"; lastname = Smith; login = admin; mail = "admin#demo.com"; status = 1; }; })
As per the docs, this is how you access the serialised JSON response:
if let json = response.result.value as? [String: Any] {
print("JSON: \(json)") // serialized json response
}
To access api_key you just need to unwrap the success and user dictionaries first and then you can access the api_key property in the user dictionary.
guard let user = json["user"] as? [String: Any],
let apiKey = user["api_key"] as? String else {
print("Failed to parse JSON")
return
}
print(apiKey)
When you get the response you can. use Mapper class of ObjectMapper library.
Create Model Class
import Foundation
import ObjectMapper
public final class LoginModel: Mappable, NSCoding {
// MARK: Declaration for string constants to be used to decode and also serialize.
private struct SerializationKeys {
static let status = "status"
static let login = "login"
static let firstname = "firstname"
static let id = "id"
static let lastname = "lastname"
static let mail = "mail"
static let apiKey = "api_key"
static let createdOn = "created_on"
static let lastLoginOn = "last_login_on"
}
// MARK: Properties
public var status: Int?
public var login: String?
public var firstname: String?
public var id: Int?
public var lastname: String?
public var mail: String?
public var apiKey: String?
public var createdOn: String?
public var lastLoginOn: String?
// MARK: ObjectMapper Initializers
/// Map a JSON object to this class using ObjectMapper.
///
/// - parameter map: A mapping from ObjectMapper.
public required init?(map: Map){
}
/// Map a JSON object to this class using ObjectMapper.
///
/// - parameter map: A mapping from ObjectMapper.
public func mapping(map: Map) {
status <- map[SerializationKeys.status]
login <- map[SerializationKeys.login]
firstname <- map[SerializationKeys.firstname]
id <- map[SerializationKeys.id]
lastname <- map[SerializationKeys.lastname]
mail <- map[SerializationKeys.mail]
apiKey <- map[SerializationKeys.apiKey]
createdOn <- map[SerializationKeys.createdOn]
lastLoginOn <- map[SerializationKeys.lastLoginOn]
}
/// Generates description of the object in the form of a NSDictionary.
///
/// - returns: A Key value pair containing all valid values in the object.
public func dictionaryRepresentation() -> [String: Any] {
var dictionary: [String: Any] = [:]
if let value = status { dictionary[SerializationKeys.status] = value }
if let value = login { dictionary[SerializationKeys.login] = value }
if let value = firstname { dictionary[SerializationKeys.firstname] = value }
if let value = id { dictionary[SerializationKeys.id] = value }
if let value = lastname { dictionary[SerializationKeys.lastname] = value }
if let value = mail { dictionary[SerializationKeys.mail] = value }
if let value = apiKey { dictionary[SerializationKeys.apiKey] = value }
if let value = createdOn { dictionary[SerializationKeys.createdOn] = value }
if let value = lastLoginOn { dictionary[SerializationKeys.lastLoginOn] = value }
return dictionary
}
// MARK: NSCoding Protocol
required public init(coder aDecoder: NSCoder) {
self.status = aDecoder.decodeObject(forKey: SerializationKeys.status) as? Int
self.login = aDecoder.decodeObject(forKey: SerializationKeys.login) as? String
self.firstname = aDecoder.decodeObject(forKey: SerializationKeys.firstname) as? String
self.id = aDecoder.decodeObject(forKey: SerializationKeys.id) as? Int
self.lastname = aDecoder.decodeObject(forKey: SerializationKeys.lastname) as? String
self.mail = aDecoder.decodeObject(forKey: SerializationKeys.mail) as? String
self.apiKey = aDecoder.decodeObject(forKey: SerializationKeys.apiKey) as? String
self.createdOn = aDecoder.decodeObject(forKey: SerializationKeys.createdOn) as? String
self.lastLoginOn = aDecoder.decodeObject(forKey: SerializationKeys.lastLoginOn) as? String
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(status, forKey: SerializationKeys.status)
aCoder.encode(login, forKey: SerializationKeys.login)
aCoder.encode(firstname, forKey: SerializationKeys.firstname)
aCoder.encode(id, forKey: SerializationKeys.id)
aCoder.encode(lastname, forKey: SerializationKeys.lastname)
aCoder.encode(mail, forKey: SerializationKeys.mail)
aCoder.encode(apiKey, forKey: SerializationKeys.apiKey)
aCoder.encode(createdOn, forKey: SerializationKeys.createdOn)
aCoder.encode(lastLoginOn, forKey: SerializationKeys.lastLoginOn)
}
}
User this model class to map your response...
Alamofire.request(serverLink!, headers: headers).responseJSON{ response in
if let responseData = Mapper< LoginModel>().map(JSONObject: response.result.value) {
print(responseData.apiKey)
} else {
print("Fail to map data")
}
}
Related
I am new in swift programing. I'm trying to learn plist file. I have a plist file which has data of Country, State and city. I want to iterate through the data of plist file. But I can't understand how to create an array or dictionary to store the data for country, state and City. Can you help me with how to manipulate the following data of plist file.
{
Country = (
{
CountryName = India;
State = (
{
City = (
Ahmedabad,
Vadodara,
Surat,
Aanand,
Bharuch
);
StateName = Gujrat;
},
{
City = (
Mumbai,
Pune,
Nagpur,
Nasik,
Thane
);
StateName = Maharastra;
},
{
City = (
Kochi,
Kanpur,
Alleppey,
Thrissur,
Thiruvananthapuram
);
StateName = Kerala;
}
);
},
// swift 3 using structure. Manually parsing of data.
struct ListData {
var countries : [Country]?
init(dict:[String:AnyObject]) {
if let countryDict = dict["Country"] as? [[String:AnyObject]] {
self.countries = parseArray(dictArray: countryDict)
}
}
func parseArray(dictArray:[[String:AnyObject]]) -> [Country] {
var array = [Country]()
for dict in dictArray {
let country = Country(dict: dict)
array.append(country)
}
return array
}
}
struct Country {
var countryName : String?
var states : [State]?
init(dict:[String:AnyObject]) {
countryName = dict["CountryName"] as? String
if let stateDict = dict["State"] as? [[String:AnyObject]] {
states = parseArray(dictArray: stateDict)
}
}
func parseArray(dictArray:[[String:AnyObject]]) -> [State] {
var array = [State]()
for dict in dictArray {
let state = State(dict: dict)
array.append(state)
}
return array
}
}
struct State {
var stateName : String?
var cities : [String]?
init(dict:[String:AnyObject]) {
self.stateName = dict["StateName"] as? String
if let cityDict = dict["City"] as? [AnyObject] {
cities = parseArray(dictArray: cityDict)
}
}
func parseArray(dictArray:[AnyObject]) -> [String] {
var array = [String]()
for dict in dictArray {
array.append(dict as! String)
}
return array
}
}
var listData : ListData? = nil
if let path = Bundle.main.path(forResource: "Property List" , ofType: "plist") {
let rootDict = NSDictionary(contentsOfFile: path) as? [String:AnyObject]
listData = ListData(dict: rootDict!)
}
// Using swift 4 and codable protocol.
struct ListData : Codable {
var countries : [Country]?
enum CodingKeys : String, CodingKey {
case countries = "Country"
}
}
struct Country : Codable {
var countryName : String?
var states : [State]?
enum CodingKeys : String, CodingKey {
case countryName = "CountryName"
case states = "State"
}
}
struct State : Codable {
var stateName : String?
var cities : [String]?
enum CodingKeys : String, CodingKey {
case stateName = "StateName"
case cities = "City"
}
}
var listData : ListData? = nil
if let url = Bundle.main.url(forResource: "Property List", withExtension: "plist") {
if let data = try? Data(contentsOf: url) {
let decoder = PropertyListDecoder()
do {
listData = try decoder.decode(ListData.self, from: data)
} catch (let err) {
print(err.localizedDescription)
}
}
}
You can use Object mapper
https://github.com/Hearst-DD/ObjectMapper
where, install the pod and then
create your class as
class State : Mappable {
var stateName: String?
var city: [String]?
required init?(map: Map) {}
func mapping(map: Map) {
stateName <- map["StateName"]
city <- map["City"]
}
}
class Country : Mappable {
var countryName: String?
var state: [State]?
required init?(map: Map) {}
func mapping(map: Map) {
countryName <- map["CountryName"]
state <- map["State"]
}
}
class CountryData: Mappable {
var countries: [Country]?
required init?(map: Map) {}
func mapping(map: Map) {
countries <- map["Country"]
}
}
get your plist content in a varibale like
var dictRoot: NSDictionary?
var countryItems: [String:AnyObject]?
if let path = Bundle.main.path(forResource: "MyCountryList" , ofType: "plist") {
dictRoot = NSDictionary(contentsOfFile: path)
}
if dictRoot != nil
{
// Your dictionary contains an array of dictionary
// Now pull an Array out of it.
countryItems = dictRoot as? [String:AnyObject]
tableView.reloadData()
}
let countryData = CountryData(JSON: countryItems)
now you can use it as you wish
My API response is look like this
{
"error": false,
"id": "6",
"user_id": 7,
"users": [
{
"user_id": 1,
"username": "spiderman"
},
{
"user_id": 7,
"username": "wonderwoman"
}
],
"info": [
{
"id": 471,
"message": "abc",
"age": 10,
}
]
}
I know how to initialize the value of id,user_id and error in NSOject. But I dont know how can I initialize the array of users and info in the same NSObject class.
Now I initialize the JSON like this
import UIKit
import SwiftyJSON
class MyItem: NSObject {
var userId : Int
var error : Bool
var id : Int
init?(dict: [String :JSON]) {
self.id = dict["id"]?.int ?? 0
self.error = dict["error"]?.bool ?? false
self.userId = dict["userId"]?.int ?? 0
}
}
Now the problem is I don't know how to initialize data inside the users and info dictionary.How should I arrange it and how can I use it in other class
Kindly give an example.
Use as below,
Root Class :-
import Foundation
import SwiftyJSON
class RootClass : NSObject, NSCoding{
var error : Bool!
var id : String!
var info : [Info]!
var userId : Int!
var users : [User]!
/**
* Instantiate the instance using the passed json values to set the properties values
*/
init(fromJson json: JSON!){
if json.isEmpty{
return
}
error = json["error"].boolValue
id = json["id"].stringValue
info = [Info]()
let infoArray = json["info"].arrayValue
for infoJson in infoArray{
let value = Info(fromJson: infoJson)
info.append(value)
}
userId = json["user_id"].intValue
users = [User]()
let usersArray = json["users"].arrayValue
for usersJson in usersArray{
let value = User(fromJson: usersJson)
users.append(value)
}
}
/**
* Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property
*/
func toDictionary() -> [String:Any]
{
let dictionary = [String:Any]()
if error != nil{
dictionary["error"] = error
}
if id != nil{
dictionary["id"] = id
}
if info != nil{
var dictionaryElements = [[String:Any]]()
for infoElement in info {
dictionaryElements.append(infoElement.toDictionary())
}
dictionary["info"] = dictionaryElements
}
if userId != nil{
dictionary["user_id"] = userId
}
if users != nil{
var dictionaryElements = [[String:Any]]()
for usersElement in users {
dictionaryElements.append(usersElement.toDictionary())
}
dictionary["users"] = dictionaryElements
}
return dictionary
}
/**
* NSCoding required initializer.
* Fills the data from the passed decoder
*/
#objc required init(coder aDecoder: NSCoder)
{
error = aDecoder.decodeObject(forKey: "error") as? Bool
id = aDecoder.decodeObject(forKey: "id") as? String
info = aDecoder.decodeObject(forKey: "info") as? [Info]
userId = aDecoder.decodeObject(forKey: "user_id") as? Int
users = aDecoder.decodeObject(forKey: "users") as? [User]
}
/**
* NSCoding required method.
* Encodes mode properties into the decoder
*/
func encode(with aCoder: NSCoder)
{
if error != nil{
aCoder.encode(error, forKey: "error")
}
if id != nil{
aCoder.encode(id, forKey: "id")
}
if info != nil{
aCoder.encode(info, forKey: "info")
}
if userId != nil{
aCoder.encode(userId, forKey: "user_id")
}
if users != nil{
aCoder.encode(users, forKey: "users")
}
}
}
User Class :-
import Foundation
import SwiftyJSON
class User : NSObject, NSCoding{
var userId : Int!
var username : String!
/**
* Instantiate the instance using the passed json values to set the properties values
*/
init(fromJson json: JSON!){
if json.isEmpty{
return
}
userId = json["user_id"].intValue
username = json["username"].stringValue
}
/**
* Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property
*/
func toDictionary() -> [String:Any]
{
let dictionary = [String:Any]()
if userId != nil{
dictionary["user_id"] = userId
}
if username != nil{
dictionary["username"] = username
}
return dictionary
}
/**
* NSCoding required initializer.
* Fills the data from the passed decoder
*/
#objc required init(coder aDecoder: NSCoder)
{
userId = aDecoder.decodeObject(forKey: "user_id") as? Int
username = aDecoder.decodeObject(forKey: "username") as? String
}
/**
* NSCoding required method.
* Encodes mode properties into the decoder
*/
func encode(with aCoder: NSCoder)
{
if userId != nil{
aCoder.encode(userId, forKey: "user_id")
}
if username != nil{
aCoder.encode(username, forKey: "username")
}
}
}
Info Class :-
import Foundation
import SwiftyJSON
class Info : NSObject, NSCoding{
var age : Int!
var id : Int!
var message : String!
/**
* Instantiate the instance using the passed json values to set the properties values
*/
init(fromJson json: JSON!){
if json.isEmpty{
return
}
age = json["age"].intValue
id = json["id"].intValue
message = json["message"].stringValue
}
/**
* Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property
*/
func toDictionary() -> [String:Any]
{
let dictionary = [String:Any]()
if age != nil{
dictionary["age"] = age
}
if id != nil{
dictionary["id"] = id
}
if message != nil{
dictionary["message"] = message
}
return dictionary
}
/**
* NSCoding required initializer.
* Fills the data from the passed decoder
*/
#objc required init(coder aDecoder: NSCoder)
{
age = aDecoder.decodeObject(forKey: "age") as? Int
id = aDecoder.decodeObject(forKey: "id") as? Int
message = aDecoder.decodeObject(forKey: "message") as? String
}
/**
* NSCoding required method.
* Encodes mode properties into the decoder
*/
func encode(with aCoder: NSCoder)
{
if age != nil{
aCoder.encode(age, forKey: "age")
}
if id != nil{
aCoder.encode(id, forKey: "id")
}
if message != nil{
aCoder.encode(message, forKey: "message")
}
}
}
The best way to do this is to create 2 different classes for user and info as follows:
class MyItem : NSObject {
var error : Bool!
var id : String!
var info : [Info]!
var userId : Int!
var users : [User]!
init(fromJson json: JSON!){
if json == nil{
return
}
error = json["error"].boolValue
id = json["id"].stringValue
info = [Info]()
let infoArray = json["info"].arrayValue
for infoJson in infoArray{
let value = Info(fromJson: infoJson)
info.append(value)
}
userId = json["user_id"].intValue
users = [User]()
let usersArray = json["users"].arrayValue
for usersJson in usersArray{
let value = User(fromJson: usersJson)
users.append(value)
}
}
}
class User : NSObject {
var userId : Int!
var username : String!
init(fromJson json: JSON!){
if json == nil{
return
}
userId = json["user_id"].intValue
username = json["username"].stringValue
}
}
class Info : NSObject {
var age : Int!
var id : Int!
var message : String!
init(fromJson json: JSON!){
if json == nil{
return
}
age = json["age"].intValue
id = json["id"].intValue
message = json["message"].stringValue
}
}
By doing this you would be able to directly access the value of user and info like for eg: MyItem.users[index].userId
Do Like this,
class MyItem: NSObject {
var userId : Int
var error : Bool
var id : Int
var users : [[String:Any]] = []
var info : [[String:Any]] = []
init?(dict: [String :JSON]) {
self.id = dict["id"]?.int ?? 0
self.error = dict["error"]?.bool ?? false
self.userId = dict["userId"]?.int ?? 0
self.users = dict["users"] ?? []
self.info = dict["info"] ?? []
}
}
No offense to the developers of SwiftyJSON, it is a great library, but in Swift 4 to decode JSON SwiftyJSON became obsolete.
With the Decodable protocol you are able to decode the JSON without any extra code.
Create one struct including the two substructs, the coding keys are only necessary to map snake_case to camelCase.
struct MyItem: Decodable {
private enum CodingKeys: String, CodingKey { case userId = "user_id", error, id, users, info}
let userId : Int
let error : Bool
let id : String
let users : [User]
let info : [Info]
struct User : Decodable {
private enum CodingKeys: String, CodingKey { case userId = "user_id", username}
let userId : Int
let username : String
}
struct Info : Decodable {
let message : String
let id, age : Int
}
}
Now decode the JSON
let jsonString = """
{
"error": false,
"id": "6",
"user_id": 7,
"users": [{"user_id": 1, "username": "spiderman"},{"user_id": 7,"username": "wonderwoman"}],
"info": [{"id": 471,"message": "abc", "age": 10}]
}
"""
do {
let data = Data(jsonString.utf8)
let decoder = JSONDecoder()
let result = try JSONDecoder().decode(MyItem.self, from: data)
for user in result.users {
print(user.userId, user.username)
}
} catch { print(error) }
I have a JSON which receives an array from an API call
Within that array are 3 other arrays:
userDetails, userStats, communities
An example of this API call is:
["communities": <__NSArrayI 0x6000002540a0>(
{
id = 5;
name = South;
},
{
id = 13;
name = HurraHarry;
},
{
id = 15;
name = EnclliffeT;
}
)
, "userStats": {
totalDraws = 3;
totalLosses = 10;
totalWins = 1;
}, "userDetails": {
id = 31;
"user_email" = "steve#gmail.com";
"user_name" = "Steve Base";
}]
I would like to store the array userStats in a variable that I can pass to another VC.
I have a global variable var userStatsArray = [AnyObject]() in my class
and the following code deals with the JSON:
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
print (json!)
if let arr = json?["communities"] as? [[String:String]] {
self.communitiesArray = arr.flatMap { $0["name"]!}
self.communityIdsArray = arr.flatMap { $0["id"]!}
}
if let dict = json?["userDetails"] as? [String:String] {
self.tempPlayerId = [dict["id"]!]
let characterArray = self.tempPlayerId.flatMap { String.CharacterView($0) }
let newPlayerId = String(characterArray)
self.playerId = newPlayerId
}
if let tempArray = json?["userStats"] as? [String:AnyObject]{
print ("here ", tempArray)
}
The print command successfully prints the userStats array with all its headers (totalWins, totalDraws, totalLosses...) -
How do I store this array into my global variable var userStatsArray = [AnyObject]() so I can pass it to another VC?
Better you create one custom class like this, and declare the array with that custom class type. then you cast your userStats object to your custom class type.
class userStats: NSObject {
var totalDraws: NSNumber?
var totalLosses: NSNumber?
var totalWins: NSNumber?
init(totalDraws: NSNumber?, totalLosses: NSNumber?, totalWins: NSNumber?) {
self.totalDraws = totalDraws
self.totalWins = totalWins
self.totalLosses = totalLosses
}
}
var userStatsArray = [userStats]()
// CHANGE YOUR CODE LIKE THIS
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:AnyObject]
print (json!)
if let arr = json?["communities"] as? [[String:String]] {
self.communitiesArray = arr.flatMap { $0["name"]!}
self.communityIdsArray = arr.flatMap { $0["id"]!}
}
if let dict = json?["userDetails"] as? [String:String] {
self.tempPlayerId = [dict["id"]!]
let characterArray = self.tempPlayerId.flatMap { String.CharacterView($0) }
let newPlayerId = String(characterArray)
self.playerId = newPlayerId
}
if let tempArray = json?["userStats"]as? userStats {
userSytatsArray.append(tempArray)
}
Take a look at ObjectMapper! With that powerful framework you can create the mappable models of your data returned by the API and let it perform the whole work for you :)
Declare your model classes like this:
class UserInfo: Mappable {
var communities : [Community]?
var stats: UserStats?
var details: UserDetails?
required init?(map: Map) {
}
func mapping(map: Map) {
communities <- map["communities"]
stats <- map["userStats"]
details <- map["userDetails"]
}
}
class Community: Mappable {
var id: Int!
var name: String!
required init?(map: Map) {
}
func mapping(map: Map) {
id <- map["id"]
name <- map["name"]
}
}
class UserStats: Mappable {
var totalDraws : Int!
var totalLosses : Int!
var totalWins : Int!
required init?(map: Map) {
}
func mapping(map: Map) {
totalDraws <- map["totalDraws"]
totalLosses <- map["totalLosses"]
totalWins <- map["totalWins"]
}
}
class UserDetails: Mappable {
var id : Int!
var email : String!
var username : String!
required init?(map: Map) {
}
func mapping(map: Map) {
id <- map["id"]
email <- map["user_email"]
username <- map["user_name"]
}
}
And later just:
let user = UserInfo(JSONString: JSONString)
I want to save the response from JSON in a file and fetch from it when the network is not available. However on trying to fetch idea by disabling the wifi, the app always crashes. Are there any other ways for offline fetching in swift except saving in database??
This is the error I am getting : Could not cast value of type 'Swift._NSContiguousString' (0x109e22320) to 'NSArray'
This is what I have done so far:
Create a model
class Directory : NSObject, NSCoding {
var data : [AnyObject]
var tid : String
var vid : String
var name : String
var imgThumbnail : String
var imgMedium : String
var imgLarge : String
var child : String
// MARK: Archiving Paths
init(data:[AnyObject],tid:String,vid:String,name:String,imgThumbnail:String,imgMedium:String,imgLarge:String,child:String) {
self.data = data ?? []
self.tid = tid ?? ""
self.vid = vid ?? ""
self.name = name ?? ""
self.imgThumbnail = imgThumbnail ?? ""
self.imgMedium = imgMedium ?? ""
self.imgLarge = imgLarge ?? ""
self.child = child ?? ""
}
// MARK: NSCoding
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(data, forKey:Constants.kData)
aCoder.encodeObject(name, forKey:Constants.Directory.kName )
aCoder.encodeObject(tid, forKey: Constants.Directory.tid)
aCoder.encodeObject(vid, forKey: Constants.Directory.vid)
aCoder.encodeObject(imgThumbnail, forKey:Constants.Directory.kImageThumbnail)
aCoder.encodeObject(imgMedium, forKey: Constants.Directory.kImageMedium)
aCoder.encodeObject(imgLarge, forKey: Constants.Directory.kImageLarge)
aCoder.encodeObject(child, forKey: Constants.Directory.kChild)
}
required convenience init?(coder aDecoder: NSCoder) {
let data = aDecoder.decodeObjectForKey(Constants.kData) as! [AnyObject]
let name = aDecoder.decodeObjectForKey(Constants.Directory.kName) as! String
let tid = aDecoder.decodeObjectForKey(Constants.Directory.tid) as! String
let vid = aDecoder.decodeObjectForKey(Constants.Directory.vid) as! String
let imgThumbnail = aDecoder.decodeObjectForKey(Constants.Directory.kImageThumbnail) as! String
let imgMedium = aDecoder.decodeObjectForKey(Constants.Directory.kImageMedium) as! String
let imgLarge = aDecoder.decodeObjectForKey(Constants.Directory.kImageLarge) as! String
let child = aDecoder.decodeObjectForKey(Constants.Directory.kChild) as! String
// Must call designated initializer.
self.init(data:data,tid:tid,vid:vid,name:name,imgThumbnail:imgThumbnail,imgMedium: imgMedium,imgLarge: imgLarge, child: child)
}
}
Code for saving and loading the data from file
class func loadSavedFile(fileName: String) -> AnyObject? {
let pathString: String = Utility.fetchFilePathString(fileName)
print("Here the pathString is \(pathString)")
if NSFileManager.defaultManager().fileExistsAtPath(pathString) {
return NSKeyedUnarchiver.unarchiveObjectWithFile(pathString)!
} else {
return "File doesn't exist"
}
return ""
}
class func saveObject(object: AnyObject, toFile fileName: String) {
let pathString: String = Utility.fetchFilePathString(fileName)
NSKeyedArchiver.archiveRootObject(object, toFile: pathString)
}
class func fetchFilePathString(fileName: String) -> String {
let pathAray: [AnyObject] = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.AllDomainsMask, true)
let pathString = pathAray.last!
return NSURL(fileURLWithPath: pathString as! String).URLByAppendingPathComponent(fileName).absoluteString
}
Checking for network connection in the view controller
var directoryArr = [Directory]()
override func viewDidLoad() {
super.viewDidLoad()
if Utility.isNetworkReachable() {
Utility.saveObject([], toFile: Constants.File.kDirectory)
self.serviceCallDirectory()
} else {
self.directorie = (Utility.loadSavedFile(Constants.File.kDirectory) as? [Directory])!
self.tableView.reloadData()
}
Service Call
func serviceCallDirectory() -> Void {
let stringUrl = Constants.baseUrl + Constants.kDirectoryUrl
WebService.getRequestAPI(stringUrl, withSuccess: {(responseDic, Statusflag,error) in
if Statusflag {
self.tableView.backgroundColor = UIColor.clearColor()
self.tableView.hidden = false
let tempInfo = responseDic![Constants.kData] as! [AnyObject]
var imgthumbnail : String = ""
var imgmedium : String = ""
var imglarge : String = ""
var name : String = ""
var child : String = ""
if tempInfo.count != 0 {
for info in tempInfo {
let tid = info[Constants.Directory.tid] as! String
let vid = info[Constants.Directory.vid] as! String
if let names = info[Constants.Directory.kName] as? String {
name = names
}
if let childs = info[Constants.Directory.kChild] as? String {
child = childs
}
if let imgthumb = info[Constants.Directory.kImageThumbnail] as? String {
imgthumbnail = imgthumb
} else {
imgthumbnail = ""
}
if let imgmediumd = info[Constants.Directory.kImageMedium] as? String {
imgmedium = imgmediumd
} else {
imgmedium = ""
}
if let imglarges = info[Constants.Directory.kImageLarge] as? String {
imglarge = imglarges
}
let myModel = Directory(
data: tempInfo,
tid: tid,
vid: vid,
name: name,
imgThumbnail: imgthumbnail,
imgMedium: imgmedium,
imgLarge: "",
child: child
)
self.directorie.append(myModel)
}
I don't know that this is the only issue, but this code
class func loadSavedFile(fileName: String) -> AnyObject? {
let pathString: String = Utility.fetchFilePathString(fileName)
print("Here the pathString is \(pathString)")
if NSFileManager.defaultManager().fileExistsAtPath(pathString) {
return NSKeyedUnarchiver.unarchiveObjectWithFile(pathString)!
} else {
return "File doesn't exist"
}
return ""
}
Either returns an object or a string. That's not very sensible. It should return a success flag or a tuple or use a completion block. When you call this function your code expects to get back an array of directory, which in a number of cases won't happen
self.directorie = (Utility.loadSavedFile(Constants.File.kDirectory) as? [Directory])!
The error in your question indicates a different kind of data mismatch. You should try not to use AnyObject, let swift help you by type checking what you're doing...
I have a User Struct that I'm casting to Json to be able to get into NSUserDefaults...
import Foundation
struct User {
var name = ""
var stores: [Store] = []
init?(json: [String: AnyObject]) {
if let name = json["name"] as? String,
storesJSON = json["stores"] as? [[String: AnyObject]]
{
self.name = name
self.stores = storesJSON.map { Store(json: $0)! }
} else {
return nil
}
}
init() { }
func toJSON() -> [String: AnyObject] {
return [
"name": name,
"stores": stores.map { $0.toJSON() }
]
}
}
and I am using a Data Manager class (Singleton) to add a new User. But I can't figure out what to pass into updateValue in my addPerson function below? Alternatively is there another way to get this object into NSUserDefaults?
import Foundation
class DataManager {
static let sharedInstance = DataManager()
var users = [String : User]()
init() {
let userDefaults = NSUserDefaults.standardUserDefaults()
if let var userFromDefaults = userDefaults.objectForKey("users") as? [String : User] {
users = userFromDefaults
}
else {
// add default values later
}
}
var userList: [String] {
var list: [String] = []
for userName in users.keys {
list.append(userName)
}
list.sort(<)
return list
}
func addPerson(newUserName: String) {
users.updateValue(User(), forKey: newUserName)
// saveData()
}
You should change your interface of the addPerson function, use addPerson(newUser: User) instead of using addPerson(newUserName: String) as #iosDev82 said:
// Because your addPerson function needs two parameters: a name and a user object
func addPerson(newUser: User) {
users.updateValue(newUser, forKey: newUser.name)
// saveData()
}
so you can:
let newName = textField.text.capitalizedString
let newUser = User(["name": newName, "stores" : []])
DataManager.sharedInstance.addPerson(newUser)
I think you already know how to create a User object. And that is what you should pass as an argument to your following function. Something like this.
var aUser = User(["name": textField.text. capitalizedString])
DataManager.sharedInstance.addPerson(aUser)
func addPerson(newUser: User) {
users[newUser.name] = newUser
// saveData()
}