Swift - json nested array not returning value - arrays

I am trying to grab the array from "imports" from the JSON file but the array is returning encoded.
[ServerName.JSONNodeValue, ServerName.JSONNodeValue, ServerName.JSONNodeValue, ServerName.JSONNodeValue, ServerName.JSONNodeValue, ServerName.JSONNodeValue]
I know the data can be seen as if I print the value of the data in the JSONNode file, it comes up as
https://servername.com/storage/sessions/00167/imports
(
"movie1.mov",
"movie3.mov",
"movie2.mov",
"._movie1.mov",
"._movie2.mov",
"._movie3.mov"
)
This isn't my code and the reason why I am struggling as I am still pretty new at swift.
My JSON file looks similar to this.
{
"id": 135
"name": Test
"angles" [
{
"id": 35,
"name": "test",
"mp4": "http:/0.0.0:3000/storage/seesion/00138/url.mp4"
}
]
"imports" [
movie1.mp4,
movie2.mp4,
movie3.mp4
]
}
Swift Code - Session File
struct Session {
var id: Int
var name: String
var angles: [Angle] = []
var imports: [Any]
extension Session {
init(fromDict dict: [String: AnyObject]){
let node = JSONNodeValue(dict)
let sessionId = node["id"].int ?? 0
self.id = sessionId
self.name = node["name"].string ?? "???"
print(name)
self.imports = node["imports"].arrayOrEmpty
self.angles = node["angles"].arrayOrEmpty.map { angleDict in
Angle(fromDict: angleDict.object!)
}
JSONnode file that handles the JSON
protocol JSONNode {
subscript(key: String) -> JSONNode { get }
var int: Int? { get }
var double: Double? { get }
var string: String? { get }
var bool: Bool? { get }
var date: Date? { get }
var array: [JSONNode]? { get }
var arrayOrEmpty: [JSONNode] { get }
var object: [String: Any]? { get }
var objectOrEmpty: [String: Any] { get }
}
class JSONNodeValue : JSONNode {
static func parse (_ data: Data) -> JSONNode {
if let root = try? JSONSerialization.jsonObject(with: data) {
return JSONNodeValue(root)
} else {
return JSONNodeNone.instance
}
}
var value: Any
init(_ value: Any) {
self.value = value
print(value) // SHOWS THE DATA I NEED
}
subscript(key: String) -> JSONNode {
if let object = value as? [String: Any], let subvalue = object[key] {
return JSONNodeValue(subvalue)
} else {
return JSONNodeNone.instance
}
}
var int: Int? {
return value as? Int
}
var double: Double? {
return value as? Double
}
var string: String? {
return value as? String
}
var bool: Bool? {
return value as? Bool
}
var date: Date? {
if let formatted = string {
return Date.fromIso8601(formatted)
} else {
return nil
}
}
var array: [JSONNode]? {
if let array = value as? [Any] {
return array.map { JSONNodeValue($0) }
} else {
return nil
}
}
var arrayOrEmpty: [JSONNode] {
return array ?? []
}
var object: [String: Any]? {
return value as? [String: Any]
}
var objectOrEmpty: [String : Any] {
return object ?? [:]
}
}
Could someone point me in the right direction or to other answered questions that could help me solve this? Thanks

The struct looks good, but remove the = [] after [Angle], but you should use Codable protocol to parse the JSON like so:
struct Session: Codable {
var id: Int
var name: String
var angles: [Angle]
var imports_dir_contents: [Any]
then create another struct to get the Angle
struct Angle: Codable
let id: Int
let name: String
let mp4: String
Then you want to parse using the Codable protocol method by passing in the data retrieved from the networking call.
do {
let newJSONDecoder = JSONDecoder()
let session = try newJSONDecoder.decode(Session.self, from:data)
let anglesArray = session.angles // or use whatever array property you want
} catch {
print("error while parsing:\(error)")
}

I solved what I was trying to achieve by adding a new a variable in the JSNODE file which then gave me ["movie1.mov", "movie3.mov", "movie2.mov", "._movie1.mov", "._movie2.mov", "._movie3.mov"]
var arrayList: [String]? {
return value as? [String]
}
Thanks for the help though.

Related

swiftUI array.first(where: not working with struct/class array

I am trying to find a string within an array using this code;
var userArray = [UserItem]()
var foundUser: String {
guard let findUser = userArray.first(where: { $0 == item.name }) else { return "Not found" }
return findUser
}
But I am getting the following error message;
"Cannot convert value of type '(String) -> Bool' to expected argument type '(UserList) throws -> Bool'"
So I tried adding a standard array;
var userArray = ["1", "Gale Dyer", "3", "4"]
and got rid of the error and the result I intended.
I assume it is because my struct or class does not conform to String but I am not sure how I fix this as adding ", String" doesn't seem to be the answer.
For reference here is the other data;
struct UserItem: Codable, Identifiable {
var id: String
var isActive: Bool
var name: String
var age: Int
var company: String
var email: String
var address: String
var about: String
// var registered: Date
var tags: [String]
var friends: [Friend]
}
struct Friend: Codable {
var id: String
var name: String
}
class UserList: ObservableObject {
#Published var items = [UserItem]()
{
didSet {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(items) {
UserDefaults.standard.set(encoded, forKey: "Items")
}
}
}
init() {
if let items = UserDefaults.standard.data(forKey: "Items") {
let decoder = JSONDecoder()
if let decoded = try? decoder.decode([UserItem].self, from: items) {
self.items = decoded
return
}
}
self.items = []
}
}
Thank you in advance
You have to check with same type in the closure of first(where:) method. Here's the fix.
var foundUser: String {
guard let findUser = userArray.first(where: { $0.name == item.name })?.name else { return "Not found" }
return findUser
}

How can I remove whole dictionary in nested array at specific index after filter some specific value

I have API response with nested array . But I can't understand how can I remove whole Dict by filtering the value .
This is the response screenshot
https://imgur.com/XIDyfYX
here is the json Resonse :- https://del.dog/lofavofogo.json
I have tried this but I don't know how to get filter nested value and remove whole dict at specific index
How to remove pairs from dictionary at specific index - Swift?
I want to remove the dict where section name are "NA"
Here is the code :-
Model Class For API Response :-
class filterclass: NSObject {
var classesID : String?
var classname : String?
var section = [filterSections]()
init(json: [String: Any]) {
if let classname = json["class"] as? String {
self.classname = classname
}
if let classesID = json["classesID"] as? String {
self.classesID = classesID
}
print("classname",classname)
if let evUserGoing = json["classsection"] as? [[String: Any]] {
if self.section.count > 0
{
self.section.removeAll()
}
for evUser in evUserGoing {
// print("evUser",evUser)
let userGoing = filterSections(json: evUser)
self.section.append(userGoing)
}
for sec in section {
let section = sec.secctionname
let setionID = sec.sectionID
}
}
}
}
class filterSections: NSObject {
var sectionID : String?
var secctionname : String?
var isSelctedSection : Bool = false
init(json: [String: Any]) {
if let sectionID = json["sectionID"] as? String {
self.sectionID = sectionID
}
if let secctionname = json["section"] as? String {
self.secctionname = secctionname
}
print("sectioname",secctionname)
}
}
API POST Method TO hit API :-
func getClassSectionAPI() {
if ReusableClass.sharedInstance.isNetworkAvailable() == true
{
ReusableClass.sharedInstance.showActivityIndicator()
let UUid = LoginUserInfo.sharedInstance.uuid!
let dictionary = ["uuid":UUid,"device_id":devicetoken,"school_id":LoginUserInfo.sharedInstance.schoolId!, "user_type":LoginUserInfo.sharedInstance.usertype!]
print(dictionary)
let encoder = JSONEncoder()
if let jsonData = try? encoder.encode(dictionary) {
if let jsonString = String(data: jsonData, encoding: .utf8) {
// print(jsonString)
let cipher:String = CryptoHelper.encrypt(input:jsonString)!;
let NewEncryption = "data=\(cipher)"
print(NewEncryption)
let hmac_md5 = cipher.hmac(algorithm: .sha512, key: kHMACKey)
print("hmac",hmac_md5)
UserDefaults.standard.set(hmac_md5, forKey: Headerkey)
Singleton.sharedInstance.getWebservicesverify(params: NewEncryption, Methodname: KFilterClassSection, data: Stringnil)
{ (result) in
DispatchQueue.main.async {
ReusableClass.sharedInstance.hideActivityIndicator()
}
if result != nil
{
do {
let jsonData = try JSONSerialization.data(withJSONObject: result)
if let json = String(data: jsonData, encoding: .utf8) {
let Dict = function.convertToDictionary(text: json)! as NSDictionary
guard let data = Dict[KData] as? String
else
{
return
}
self.baseDict = data
}
}
catch {
}
guard let output = CryptoHelper.decrypt(input:self.baseDict)
else
{
return
}
print(output)
let mainDict = function.convertToDictionary(text: output)! as NSDictionary
let status = mainDict[KStatus] as! NSInteger
if(status == 1)
{
DispatchQueue.main.async {
print("Main dict",mainDict)
guard let messageArray = mainDict["data"] as? [[String: Any]] else{
return
}
if self.arrayClasSection.count > 0
{
self.arrayClasSection.removeAll()
}
print("Main dict",messageArray)
for arr in messageArray {
let obj = filterclass.init(json: arr)
if let index = self.arryFilterTemperary.index(where: { $0.classname == obj.classname }) {
// let filtered = self.arryFilterTemperary.filter { $0.classname == "NA" }
obj.section = self.arryFilterTemperary[index].section
self.arrayClasSection.append(obj)
for sec in self.arryFilterTemperary[index].section {
let section = sec.sectionID
let sectionName = sec.secctionname
self.NASection = sec.secctionname!
print(self.NASection)
self.selectedNASectionID = sec.sectionID!
// let test = self.arryFilterTemperary[index].section.filter { !$0.value.contains("") }
// print(test)
}
}
else
{
self.arrayClasSection.append(obj)
}
}
ReusableClass.sharedInstance.hideActivityIndicator()
self.tableFilter.reloadData()
}
}
I want to append the data to array but before appending I want to
filter that "NA" value dict from the array
Since this is your first question I go to some greater length in answering it than usual. Playgrounds are an exceptional way to demonstrate your problem, so you should always try to compose your questions in a form of one. I will post my answer directly from the Playground I have done.
With that out of the way lets get to the question. Your main problem seems to be that you tried an ill fated JSONSerialization "shortcutt" route. This looks cheap from the outside, but working with the unavoidable optionality of a [String:Any] comes at a high cost in a language like Swift. The way to go is the brilliant Codable protocol, at least in my opinion. Once you define your data structure properly Xcode has so much more possibilities to guide you through the APIs that writing your filter code becomes a piece of cake.
Enough of the ranting, let's get to the pizza.
import UIKit
let dataStr = """
{
"status":1,
"message":"Class and sections list",
"data":[
{
"classsection":[
{
"section":"A",
"sectionID":"1",
"classesID":"1"
},
{
"section":"B",
"sectionID":"3",
"classesID":"1"
}
],
"class":"First",
"classesID":"1"
},
{
"classsection":[
{
"section":"A",
"sectionID":"2",
"classesID":"2"
},
{
"section":"B",
"sectionID":"7",
"classesID":"2"
}
],
"class":"Second",
"classesID":"2"
},
{
"classsection":[
{
"section":"A",
"sectionID":"20",
"classesID":"15"
}
],
"class":"Third",
"classesID":"15"
},
{
"classsection":[
{
"section":"NA",
"sectionID":"33",
"classesID":"22"
}
],
"class":"Pre Nursery",
"classesID":"22"
},
{
"classsection":[
{
"section":"NA",
"sectionID":"34",
"classesID":"23"
},
{
"section":"A",
"sectionID":"35",
"classesID":"23"
},
{
"section":"B",
"sectionID":"36",
"classesID":"23"
},
{
"section":"C",
"sectionID":"37",
"classesID":"23"
}
],
"class":"Fourth four",
"classesID":"23"
},
{
"classsection":[
{
"section":"NA",
"sectionID":"38",
"classesID":"24"
}
],
"class":"Fifth",
"classesID":"24"
},
{
"classsection":[
{
"section":"NA",
"sectionID":"39",
"classesID":"25"
}
],
"class":"sixth 6th",
"classesID":"25"
}
]
}
"""
struct Section: Codable {
let section, sectionId, classesId: String
enum CodingKeys: String, CodingKey {
case sectionId = "sectionID"
case classesId = "classesID"
case section
}
}
struct Class1: Codable {
let classsection: [Section]
let clazz, classesId: String
private enum CodingKeys: String, CodingKey {
case classsection
case clazz = "class"
case classesId = "classesID"
}
}
struct Response: Codable {
let status: Int
let message: String
let data: [Class1]
func filterSections(notMatching filterVal: String) -> Response {
let filteredData = data.map { (clazz) -> Class1 in
let filteredSections = clazz.classsection.filter { (sect) -> Bool in
sect.section != filterVal
}
return Class1(classsection: filteredSections, clazz: clazz.clazz, classesId: clazz.classesId)
}
return Response(status: status, message: message, data: filteredData)
}
}
let jsonData = dataStr.data(using:.utf8)!
do {
let res = try JSONDecoder().decode(Response.self, from: jsonData)
let filteredResponse = res.filterSections(notMatching: "NA")
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
print(String(data:try encoder.encode(filteredResponse), encoding: .utf8)!)
} catch {
print(error)
}
As you can see your data structure is easily defined and the filtering code is really easy to understand once you wrap your head around the lambdas (which you should). The playground will output nicely formatted JSON as an answer, this way it is easy to check that your code does the right thing without all the messy parts of asynchronous communication (which are still nicely done in Swift).
Here's my last tipp of the day: Always try to isolate your problem as much as possible if you post a question on StackOverflow. I think your question carried too much legacy, you should whittle it down for the next one. This will improve your chances for a quick answer.

Swift 4.1 Encodable/Decodable Nested Array AND Dictionary

Need more help with json, any suggestions on how to lay this out?
Should players_loop be added in where I put it, etc... been going in circles for awhile.
struct:
struct LMSRequest: Decodable {
let id : Int
let method : String
let result : [String:Result]
let params : [Param]
}
struct players_loop: Decodable {
let uuid : String
let ip : String
let playerid : String
let connected : String
let firmware : String
let displaytype : String
let power : Int
let name : String
let playerindex : String
let canpoweroff : Int
let isplayer : Int
let seq_no : Int
let isplaying : Int
let modelname : String
let model : String
}
enum Result: CustomStringConvertible {
case string(String)
case int(Int)
case array([Result])
case players_loop([players_loop])
var description: String {
switch self {
case let .string(string): return string
case let .int(int): return "\(int)"
case let .players_loop(players_loop): return "\(players_loop)"
//case let .double(double): return "\(double)"
//case let .number(number): return "\(number)"
case let .array(array): return "\(array)"
}
}
}
extension Result: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let string = try? container.decode(String.self) {
self = .string(string)
} else if let int = try? container.decode(Int.self) {
self = .int(int)
//} else if let double = try? container.decode(Double.self) {
//self = .double(double)
} else {
self = .array(try container.decode([Result].self))
}
}
}
extension Result {
var stringValue: String? { if case let .string(value) = self { return value } else { return nil } }
var intValue: Int? { if case let .int(value) = self { return value } else { return nil } }
//var doubleValue: Double? { if case let .double(value) = self { return value } else { return nil } }
var arrayValue: [Result]? { if case let .array(value) = self { return value } else { return nil } }
subscript(_ index: Int) -> Result? {
return arrayValue?[index]
}
}
enum Param: CustomStringConvertible {
case string(String)
case int(Int)
case array([Param])
var description: String {
switch self {
case let .string(string): return string
case let .int(int): return "\(int)"
case let .array(array): return "\(array)"
}
}
}
extension Param: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let string = try? container.decode(String.self) {
self = .string(string)
} else if let int = try? container.decode(Int.self) {
self = .int(int)
} else {
self = .array(try container.decode([Param].self))
}
}
}
extension Param {
var stringValue: String? { if case let .string(value) = self { return value } else { return nil } }
var intValue: Int? { if case let .int(value) = self { return value } else { return nil } }
var arrayValue: [Param]? { if case let .array(value) = self { return value } else { return nil } }
subscript(_ index: Int) -> Param? {
return arrayValue?[index]
}
}
json:
let json = """
{
"id": 1,
"method": "slim.request",
"result": {
"mac": "B8:27:EB:7A:FA:4B",
"uuid": "e54389e6-7f63-4aac-aa83-a199226279f4",
"other player count": 0,
"info total artists": 6018,
"version": "7.9.1",
"info total albums": 6327,
"info total songs": 71808,
"lastscan": "1528917689",
"info total genres": 553,
"player count": 2,
"players_loop": [
{
"model": "squeezelite",
"modelname": "SqueezeLite",
"seq_no": 0,
"isplaying": 1,
"isplayer": 1,
"canpoweroff": 1,
"connected": 1,
"firmware": "v1.8.7-1052",
"playerindex": "-",
"displaytype": "none",
"power": 1,
"name": "piCorePlayer",
"playerid": "b8:27:eb:7d:09:80",
"uuid": null,
"ip": "10.2.2.21:47100"
}
]
},
"params": [
"b8:27:eb:db:6d:62",
[
"serverstatus",
"-",
1,
"tags:GPASIediqtymkovrfijnCYXRTIuwxNlasc"
]
]
}
""".data(using: .utf8)!
test:
do {
let decoder = JSONDecoder()
//decoder.keyDecodingStrategy = .convertFromSnakeCase
let lms = try decoder.decode(LMSRequest.self, from: json)
print(lms)
let inner = lms.params[1]
print(type(of: lms.params[1][0]))
print(inner[3] as Any)
} catch let jsonErr {
print("Failed to decode:", jsonErr)
}
Failed to decode: typeMismatch(Swift.Array,
Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue:
"result", intValue: nil), _DictionaryCodingKey(stringValue:
"players_loop", intValue: nil), _JSONKey(stringValue: "Index 0",
intValue: 0)], debugDescription: "Expected to decode Array but
found a dictionary instead.", underlyingError: nil))
Params section works great and is in the gist, answered here:
Swift 4.1 Codable/Decodable Nested Array
So I used Params as the starting point for "Results" --> but now trying to add in players_loop.
Thanks!!!
https://gist.github.com/sckramer/5b90d3b15eef2c19196abab2d7698e70
You have several issues. First of all, you need to be aware of the optional fields. From your attached JSON, it's clearly seen that uuid inside players_loop can be null. So this field should be optional as well in your model.
I purposefully changed the name of the struct to reflect Swift identifier convention (Type's name should start with UpperCase).
struct PlayersLoop: Decodable {
let uuid : String? // can take null
let ip : String
let playerid : String
let connected : Int
let firmware : String
let displaytype : String
let power : Int
let name : String
let playerindex : String
let canpoweroff : Int
let isplayer : Int
let seq_no : Int
let isplaying : Int
let modelname : String
let model : String
}
Then in the decodable requirement conformance of your Result enum you need to add another case for your PlayersLoop structure.
extension Result: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let string = try? container.decode(String.self) {
self = .string(string)
} else if let int = try? container.decode(Int.self) {
self = .int(int)
} else if let playersLoop = try? container.decode([PlayersLoop].self) {
self = .players_loop(playersLoop)
} else {
self = .array(try container.decode([Result].self))
}
}
}
Now, aside from your issues here, you should be more explicit when providing custom initializer for decodable requirement. As soon as you use try? you are saying to the compiler
"I don't care if this fails"
So you should be handling the error cases as well in the first place. If you did so, you wouldn't be in the position of posting this issue as a question at all.

Firebase array became nil after loop in Swift

I'm trying to append element to array but it returns empty array.
What I'm trying to do is put elements that match up with tags user selected.
To achieve that, first I created model.
//Model
import UIKit
import Firebase
struct Team {
var key: String
var teamName: String
var league: String
var lat: Double
var lng: Double
init(snapshot: DataSnapshot) {
self.key = snapshot.key
self.teamName = (snapshot.value as! NSDictionary)["teamName"] as? String
self.league = (snapshot.value as! NSDictionary)["league"] as? String ?? ""
self.lat = (snapshot.value as! NSDictionary)["lat"] as? Double ?? 0
self.lng = (snapshot.value as! NSDictionary)["lng"] as? Double ?? 0
}
}
firebase structure looks like this.
{
"tags": {
"NewYork": {
uid1: 1
uid2: 1
uid3: 1
},
"baseball": {
uid1: 1
}
}
}
First, I fetched uids that match up with the tags. Then retrieve team's info based on uids that matched up with. If the same uid comes in like uid1 above, I want Xcode to print something. To do that I implemented like so(is there a better way?) but it's never been executed because results.count is always 0 even if after appended. However right after append method(I commented //here) it returns team's info properly.
func filterTeam(filterTag: FilteredTags) {
let tag = filterTag.selectedTag.components(separatedBy: "/") //this returns "NewYork" and "baseball"
var results = [Team]()
tag.forEach { (key) in
ref.child("tags").child(key).observe(.value, with: { (snapshot) in
guard let dictionary = snapshot.value as? [String:Any] else { return }
dictionary.forEach({ (uid,_) in
if results.count == 0 {
ref.child("teams").child(uid).observe(.value, with: { (snapshots) in
let team = Team(snapshot: snapshots)
results.append(team)
//here
print(results)
}, withCancel: nil)
} else {
for result in results {
if result.key == uid {
print("same uid!!")
} else {
ref.child("teams").child(uid).observe(.value, with: { (snapshots) in
let team = Team(snapshot: snapshots)
results.append(team)
}, withCancel: nil)
}
}
}
})
}, withCancel: nil)
}
}//func
How can I append properly and achieve what I want to do.
Thank you in advance!

struggling with JSON parsing in swift

I am trying to load data in JSON format from my server into IOS application.
Here is my JSON:
[
{
"BankName": "bank1",
"CurrencyName": "cur1",
"SellRate": "0.65",
"BuyRate": "0.55",
"OfficialRate": "0.6"
},
{
"BankName": "bank1",
"CurrencyName": "cur2",
"SellRate": "1.65",
"BuyRate": "1.55",
"OfficialRate": "1.6"
}
]
There are 2 files in my project:
1:
import Foundation
class Shot {
var bankName: String!
var currencyName: String!
var sellRate: String!
var buyRate: String!
var offRate: String!
init (data: NSDictionary) {
self.bankName = getStringFromJSON(data, key:"BankName")
self.currencyName = getStringFromJSON(data, key:"CurrencyName")
self.sellRate = getStringFromJSON(data, key:"SellRate")
self.buyRate = getStringFromJSON(data, key:"BuyRate")
self.offRate = getStringFromJSON(data, key: "OfficialRate")
}
func getStringFromJSON(data: NSDictionary, key: String) -> String {
if let info = data[key] as? String{
return info
}
return ""
}
}
2:
import Foundation
class JsonTest {
func loadJson(completion: ((AnyObject) -> Void)!) {
var urlString = "http://a.com/g.php"
let session = NSURLSession.sharedSession()
let sourceUrl = NSURL(string: urlString)
var task = session.dataTaskWithURL(sourceUrl!){
(data, response, error) -> Void in
if error != nil {
println(error.localizedDescription)
} else {
var error: NSError?
var jsonData = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &error) as NSArray
var shots = [Shot]()
println(jsonData)
for shot in jsonData{
let shot = Shot(data: shot as NSDictionary)
shots.append(shot)
}
println(shots) //[jsontest.Shot, jsontest.Shot]
}
}
task.resume()
}
}
I am trying to populate array automatically when my app starts. To do it I have a code in my mainViewController class.
override func viewDidLoad() {
super.viewDidLoad()
let api = JsonTest()
api.loadJson(nil)
}
The problem occurs when I try to print shots variable in the second file.
it returns [jsontest.Shot, jsontest.Shot] when I was expecting the array of dictionaries.
println(jsonData) works fine and shows JSON data from URL.
Can anybody advise what is wrong in my program?
"shots" is an array of instances of Shot, not a dictionary:
class Shot {
var bankName: String!
var currencyName: String!
var sellRate: String!
var buyRate: String!
var offRate: String!
init (data: NSDictionary) {
self.bankName = getStringFromJSON(data, key:"BankName")
self.currencyName = getStringFromJSON(data, key:"CurrencyName")
self.sellRate = getStringFromJSON(data, key:"SellRate")
self.buyRate = getStringFromJSON(data, key:"BuyRate")
self.offRate = getStringFromJSON(data, key: "OfficialRate")
}
func getStringFromJSON(data: NSDictionary, key: String) -> String {
if let info = data[key] as? String{
return info
}
return ""
}
}
var shots = [Shot]()
let urlString = "http://almazini.lt/getrates.php"
let sourceUrl = NSURL(string: urlString)
// Using NSData instead of NSURLSession for experimenting in Playground
let data = NSData(contentsOfURL: sourceUrl!)
var error: NSError?
// As I'm using Swift 1.2 I had to change "as" with "as!"
let jsonData = NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers, error: &error) as! NSArray
for shot in jsonData{
let shot = Shot(data: shot as! NSDictionary)
shots.append(shot)
}
println(shots[0].bankName)
Update for Swift 2
var shots = [Shot]()
let urlString = "http://almazini.lt/getrates.php"
// Using NSData instead of NSURLSession for experimenting in Playground
if let sourceUrl = NSURL(string: urlString) {
NSURLSession.sharedSession().dataTaskWithURL(sourceUrl, completionHandler: { (data, response, error) in
if error == nil {
if let data = data, jsonData = try? NSJSONSerialization.JSONObjectWithData(data, options: []), jsonArray = jsonData as? [NSDictionary] {
for item in jsonArray {
let shot = Shot(data: item)
shots.append(shot)
}
print(shots[0].bankName)
} else {
print("no JSON data")
}
} else {
print(error!.localizedDescription)
}
}).resume()
}
Seems like there are two problems:
You're trying to use println to debug instead of setting a breakpoint and checking your objects values.
You have not created a description or debugDescription property for your object, so println on your object is just using some default implementation.
shots is an array of your custom object, so when you call println, it's using the description for Array, which prints out the objects in the array, comma separated, and within square brackets.
The default description property for classes in Swift just prints the class name.
Ideally, you should just use a break point to check the values of your object to be certain it initialized correctly, but if it's actually important to get them to print right, it's only a matter of implementing the description property:
override var description: String {
get {
// build and return some string that represents your Shot object
}
}

Resources