Map function explanation - arrays

Someone can explain me that piece of code because I can't understand well. I find this code and I can't understand notably this line : Room(dict: $0)
var rooms: [Room] = [] // The globale variable
func refresh() {
let request = URLRequest(url: URL(string: "\(Config.serverUrl)/rooms")!)
NSURLConnection.sendAsynchronousRequest(request, queue: OperationQueue.main, completionHandler: { resp, data, err in
guard err == nil else {
return
}
let rooms = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions()) as! [[String: AnyObject]]
self.rooms = rooms.map {
Room(dict: $0) // I can't understand this line
}
self.tableView.reloadData()
})
}
My Room struct:
struct Room {
var key: String
var title: String
var cat: String!
init(dict: [String: AnyObject]) {
title = dict["title"] as! String
key = dict["key"] as! String
cat = dict["cat"] as! String
}
init(key: String, title: String, cat: String) {
self.key = key
self.title = title
self.cat = cat
}
func toDict() -> [String: AnyObject] {
return [
"title": title as AnyObject,
"key": key as AnyObject,
"cat": cat as AnyObject
]
}
}
If someone can help me to understand and explain it, thank you

The map function loops over every item in a collection, and applies an operation to each element in the collection.
This piece of code
self.rooms = rooms.map {
Room(dict: $0)
}
is a short form of this.
// `dict` paramater is `$0` in shorter form
self.rooms = rooms.map { (dict : [String: AnyObject]) -> Room in
return Room(dict: dict)
}

Related

extend an Array of Dictionary<String, Any> Swift 3

var dicts = [["key1": "value1", "key2": "value2"]]
dicts.values(of: "key1") // prints - value1
I am working on a project where I want to store the array of dictionary and then fetch the data from there on condition if array of dictionary contains the particular value.
Swift 3.0
You can try this way.
var dicts:[[String:Any]] = []
var check:Bool = false
dicts = [["search_date": "17/03/17", "search_title": ""],["search_date": "17/02/19", "search_title": "parth"],["search_date": "20/02/19", "search_title": "roy"]]
for item in dicts {
if let title = item["search_title"] as? String {
if title == "parth" {
check = true
break
}else {
check = false
}
}
else {
check = false
}
}
print(check)
We can Use Model to solve the Problem
class Person: NSObject, NSCoding {
let name: String
let age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
required init(coder decoder: NSCoder) {
self.name = decoder.decodeObject(forKey: "name") as? String ?? ""
self.age = decoder.decodeInteger(forKey: "age")
}
func encode(with coder: NSCoder) {
coder.encode(name, forKey: "name")
coder.encode(age, forKey: "age")
}
}
Class
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// setting a value for a key
let newPerson = Person(name: "Joe", age: 10)
var people = [Person]()
people.append(newPerson)
let encodedData = NSKeyedArchiver.archivedData(withRootObject: people)
UserDefaults.standard.set(encodedData, forKey: "people")
// retrieving a value for a key
if let data = UserDefaults.standard.data(forKey: "people"),
let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Person] {
myPeopleList.forEach({print( $0.name, $0.age)}) // Joe 10
} else {
print("There is an issue")
}
}
}
All Thanks to Leo Dabus
[Link] (https://stackoverflow.com/a/37983027/3706845)
Your question is very vague. But what I understood is that you want to filter the array of dictionaries so it only contains dictionaries that have a certain value, and this can be done this way:
let filteredDicts = dicts.filter({ $0.values.contains("value2") })

Swift 3 JSON Array to Dictionary

I have a JSON result from Alamofire and SwiftyJSON and am trying to create a dictionary from it to create an array
JSON Result
JSON: [
{
"p_589b6a49a0bfd" : {
"path" : "\/uploads\/588fa43eba3c9\/588fa43eba3c9_1486580297.jpg",
"likes" : "0",
"userid" : "588fa43eba3c9",
"caption" : "Bae",
"comments" : "0",
"date" : "1486580297"
}
},
{
"p_589b7f1c540f1" : {
"path" : "\/uploads\/588fa43eba3c9\/588fa43eba3c9_1486585628.jpg",
"likes" : "0",
"userid" : "588fa43eba3c9",
"caption" : "Hot stuff bitch ",
"comments" : "0",
"date" : "1486585628"
}
}
]
Request/Response
Alamofire.request(BASE_URL + "index.php/feed/build", method: .get, headers: headers).responseJSON { response in
switch response.result {
case .success(let value):
let json = JSON(value)
print("JSON: \(json)")
case .failure(let error):
print(error)
}
}
I have then set up a simple class called 'FeedPost' which will store each of the elements in JSON response (this is the function in the FeedPost class)
init(postid: String, postData: Dictionary<String, AnyObject>) {
self._postid = postid
if let caption = postData["caption"] as? String {
self._caption = caption
}
if let path = postData["path"] as? String {
self._path = path
}
if let likes = postData["likes"] as? Int {
self._likes = likes
}
if let comments = postData["comments"] as? Int {
self._comments = comments
}
if let userid = postData["userid"] as? String {
self._userid = userid
}
if let date = postData["date"] as? String {
self._date = date
}
}
I need to somehow cycle through the JSON to create a dictionary to pass to FeedPost then add each FeedPost to another array called Posts during the request. The string that starts with 'p_' I want to use as the postid
With Alamofire response you have used SwiftyJSON and with your FeedPost init you are using swift native dictionary. So I'm suggesting you to either work with SwiftyJSON or with swift's native type. Since you have already added init with dictionary I'm answering your answer with native type.
Alamofire.request(BASE_URL + "index.php/feed/build", method: .get, headers: headers).responseJSON { response in
switch response.result {
case .success(let value):
If let dic = value as? [String: Any],
let array = DIC["JSON"] as? [[String: Any]] {
for item in array {
for (key, value) in item {
If let subDic = value as? [String: Any] {
let obj = FeedPost(postid: key, postData: subDic)
}
}
}
}
print("JSON: \(json)")
case .failure(let error):
print(error)
}
}
Note: Correct Dictionary notation for JSON in swift 3 is [String: Any] not [String: AnyObject] so change your init parameter postData's type to [String: Any].
Below is the code which can be used for your case, This code is copied from playgrounds.
import UIKit
typealias JSONDictionary = [String: AnyObject]
class Post {
let id: String
let userId: String?
let date: Double?
let caption: String?
let comments: Double?
let likes: Double?
let path: String?
init?(with dictionary: JSONDictionary) {
guard let postId = dictionary.keys.first, let postInfo = dictionary[postId] as? JSONDictionary else { return nil }
self.id = postId
self.userId = postInfo["userid"] as? String
self.date = postInfo["date"] as? Double
self.caption = postInfo["caption"] as? String
self.comments = postInfo["comments"] as? Double
self.likes = postInfo["likes"] as? Double
self.path = postInfo["path"] as? String
}
}
Parsing JSON array will be like this.
case .success(let value):
let jsonArray = value["JSON"] as? [JSONDictionary]
let posts = jsonArray?.flatMap(Post.init(with:))
print("Posts \(posts)"
case .failure: break
I have tried this using a local JSON file in a Playgrounds & code was something like this.
let url = Bundle.main.url(forResource: "data", withExtension: "json")
let data = try! Data(contentsOf: url!)
let jsonArray = try! JSONSerialization.jsonObject(with: data , options: .allowFragments) as? [JSONDictionary]
let posts = jsonArray?.flatMap(Post.init(with:))

serializing array to object in swift

i have the following object class:
class NewsItem: NSObject {
var storyCategory: String?
var titleText: String?
var paragraph1: String?
var paragraph2: String?
var featureImage: String?
var secondImage: String?
var storyDate: String?
var majorReference: String?
var fact: String?
var actualFeatureImage: UIImage? // Using these two to pass the image from home to story view
var actualSecondImage: UIImage?
var referencesArray = [AnyObject]()
...
init?(dictionary: [String: AnyObject]) {
guard
let storyCategory = dictionary["category"] as? String,
let titleText = dictionary["title"] as? String,
let paragraph1 = dictionary["paragraph1"] as? String,
let paragraph2 = dictionary["paragraph2"] as? String,
let featureImage = dictionary["headerImage"] as? String,
let storyDate = dictionary["date"] as? String,
let majorReference = dictionary["majorReference"] as? String,
let secondImage = dictionary["secondImage"] as? String
else {
return nil
}
self.storyCategory = storyCategory
self.titleText = titleText
self.paragraph2 = paragraph2
self.paragraph1 = paragraph1
self.featureImage = featureImage
self.storyDate = storyDate
self.majorReference = majorReference
self.fact = dictionary["fact"] as? String //if there's a fact in the dict, it will be assigned and if not there'll be nil
self.secondImage = secondImage
let referenceObject = dictionary["reference"] as? [[String: AnyObject]]
for object in referenceObject! {
self.referencesArray.append(object)
//print(object)
}
//bellow is a snippet from the method that's serializing the JSON data
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
if let newsArticles = json["stories"] as? [[String: AnyObject]] {
for article in newsArticles {
let newsArticle = NewsItem(dictionary: article)
newsItems.append(newsArticle!)
}
}
} catch {
print("error in the news items delivery: \(error)")
let displayError = EHPlainAlert(title: "hmmm...", message: "\(error)", type: ViewAlertError)
displayError.show()
}
}
in the backend of the app, i have JSON objects and one of the values of each of the objects is as follows:
... "reference" : [
{
"refName": "CNN",
"refURL": "http://edition.cnn.com/2016/07/19/football/brexit-effect-on-english-premier-league/index.html"
},
{
"refName": "Telegraph",
"refURL": "http://www.telegraph.co.uk/football/2016/06/21/what-would-brexit-mean-for-the-premier-league/"
}
], ...
i don't know if i have the JSON wrong o' something but what i intend to have is an array of references, each reference having a reference name(refName) and the url of the reference (refURL).
my question is, what would be the best method to have the JSON object above be added to the referencesArray in my object class. Would it be better to use a dictionary instead of an array? if so, how should i re-write my code?
if you need any more details about the code, ask and ye shall receive an update. Thanks!
EDIT
Here's the JSON in full :
{
"stories" : [
{
"title" : "English Premier League vs BREXIT: Who will win?",
"headerImage" : "http://i2.cdn.turner.com/cnnnext/dam/assets/160117112140-rooney-goal-exlarge-169.jpg",
"category" : "Sports",
"paragraph1" : "Paragraph text",
"paragraph2" : "More text goes here",
"date" : "21st July",
"majorReference" : "CNN",
"reference" : [
{
"refName": "CNN",
"refURL": "http://edition.cnn.com/2016/07/19/football/brexit-effect-on-english-premier-league/index.html"
},
{
"refName": "Telegraph",
"refURL": "http://www.telegraph.co.uk/football/2016/06/21/what-would-brexit-mean-for-the-premier-league/"
}
],
"secondImage" : "http://www.telegraph.co.uk/content/dam/football/2016/06/14/02-leicester-afp-xlarge_trans++Wy_u4a9GUNQgLIY2EGV3qvLCN329DeTLuwi-bwi35Bo.jpg",
"fact" : "Talent will go missing"
}, ...
Thats just one story... after the comma, is another story.
First, define a data model for your reference:
struct NewsItemReference {
var refName: String
var refURL: NSURL
}
Then modify your NewsItem class as below:
class NewsItem: NSObject {
var referencesArray = [NewsItemReference]()
init?(dictionary: [String: AnyObject]) {
...
if let references = dictionary["reference"] as? [[String: AnyObject]] {
for object in references {
guard let refName = object["refName"] as? String,
let refURLString = object["refURL"] as? String,
let refURL = NSURL(string: refURLString) else {
continue
}
self.referencesArray.append(NewsItemReference(refName: refName, refURL: refURL))
}
}
}
If you see yourself quickly outgrowing this model (the code is too verbose), take a look at some JSON-to-object mapping framework like ObjectMapper.

JSON on Swift: Array to String/TextField Text

I have problem with JSON Array that I want to be display on textfield. JSON is taken from URL. This is JSON structure:
{
description = „This is short decripton”;
);
more-description = (
„this is first line”,
„this is second line”,
„third line”,
„etc”,
„etc”
);
one-more-description = (
„this is first line”,
„this is second line”,
„third line”,
„etc”,
„etc”
);
And this is my code:
import UIKit
class RecipeViewController: UIViewController {
#IBOutlet weak var descriptionTextField: UITextView!
#IBOutlet weak var more-descriptionTextField: UITextView!
#IBOutlet weak var one-more-descriptionTextField: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let urlAsString = "http://JSON-Address.com"
let url = NSURL(string: urlAsString)!
let urlSession = NSURLSession.sharedSession()
let jsonQuery = urlSession.dataTaskWithURL(url, completionHandler: { data, response, error -> Void in
do {
if let jsonDate = data, let jsonResult = try NSJSONSerialization.JSONObjectWithData(jsonDate, options: []) as? NSDictionary {
print(jsonResult)
let jsonDescription = jsonResult["description"] as? String
print("result: \(jsonDescription)")
let jsonMoreDescrp: AnyObject? = jsonResult["more-description"] as? Array<AnyObject>
print("result: \(jsonMoreDescrp)")
let jsonOneMoreDescrp: AnyObject? = jsonResult["one-more-description"] as? Array<AnyObject>
print("result: \(jsonOneMoreDescrp)")
dispatch_async(dispatch_get_main_queue(),{
self.descriptionTextField.text = jsonDescription
self.more-descriptionTextField.text = jsonMoreDescrp as? String
self.one-more-descriptionTextField.text = jsonOneMoreDescrp as? String
});
}
} catch let error as NSError {
print(error)
}
})
jsonQuery.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
The problem is with jsonMoreDescrp & jsonOneMoreDescrp. Althought I've changed it to String, after running Xcode the result is empty. jsonDescription of course works, but this is just simple string.
I know I'm doing something wrong with Array, but - can you tell me what?
jsonMoreDescrp & jsonOneMoreDescrp are array. so, you can call like this
self.more-descriptionTextField.text = jsonMoreDescrp[indexValue] as? String
self.one-more-descriptionTextField.text = jsonOneMoreDescrp[indexValue] as? String
Hope this will help you.
Try this way, if it not works comment me the error you come across.
self.more-descriptionTextField.text = jsonMoreDescrp[indexValue].stringValue
self.one-more-descriptionTextField.text = jsonOneMoreDescrp[indexValue].stringValue
indexValue is the key of the value you want in the json.
[Updated] As Sudhir noticed there is also error in code, try this to show comma separated strings:
dispatch_async(dispatch_get_main_queue(),{
self.descriptionTextField.text = jsonDescription
self.more-descriptionTextField.text = (jsonMoreDescrp as? [String])?.joinWithSeparator(",") ?? ""
self.one-more-descriptionTextField.text = (jsonOneMoreDescrp as? [String])?.joinWithSeparator(",") ?? ""
});
Validate JSON structure online before using http://jsonlint.com/
Valid JSON:
{
"description": "This is short decription",
"more-description": [
"this is first line",
"this is second line",
"third line",
"etc",
"etc"
],
"one-more-description": [
"this is first line",
"this is second line",
"third line",
"etc",
"etc"
]
}
try this code, it is much easy to use.
First of all parse all elements of map to the variables and than do what you want with knowing structure of just created variables.
let task = session.dataTask(with: url!) {
(data, response, error) in
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String : AnyObject]
if let desc = json["description"] as? String,
let moreDesc = json["more-description"] as? [String],
let oneMoreDesc = json["one-more-description"] as? [String] {
dispatch_async(dispatch_get_main_queue(),{
self.descriptionTextField.text = moreDesc
self.more-descriptionTextField.text = moreDesc.joinWithSeparator("/n")
self.one-more-descriptionTextField.text = oneMoreDesc.joinWithSeparator("/n")
});
}
} catch let error {
print (error)
}
}
task.resume()
I have not tested it, but it should work. Feel free to ask.

Swift when appending custom class to array all previous values overwritten

I have a custom class called Subject, which I am trying to initialize versions of and append to a array, however when I append one to a array it overwrites all the Subjects all ready in there. For example this code
var things:[Subject] = []
things.append(Subject(initName: "1", initTeacher: "1", initClassroom: "1"))
things.append(Subject(initName: "2", initTeacher: "2", initClassroom: "2"))
print(things[0].name)
print(things[1].name)
is printing Optional("2") Optional("2") when it should be printing 'Optional("1") Optional("2")'
This is the code for my custom class
class Subject: NSManagedObject{
var name: String?
var teacher: String?
var classroom: String?
init(initName: String, initTeacher: String, initClassroom: String){
name = initName
teacher = initTeacher
classroom = initClassroom
}
func save() -> Bool{
if(name == "" || teacher == "" || classroom == ""){
return false
}else{
let appDelgate = UIApplication.sharedApplication().delegate as? AppDelegate
let managedContext = appDelgate?.managedObjectContext
let entity = NSEntityDescription.entityForName("Subject", inManagedObjectContext: managedContext!)
let subject = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: managedContext)
subject.setValue(name, forKey: "name")
subject.setValue(teacher, forKey: "teacher")
subject.setValue(classroom, forKey: "classroom")
do{
try managedContext?.save()
}catch let error as NSError{
print("Failed because of \(error)")
}
return true
}
}
func edit(newName: String, newTeacher: String, newClassroom: String) -> Bool{
let appDelgate = UIApplication.sharedApplication().delegate as? AppDelegate
let managedContext = appDelgate?.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Subject")
fetchRequest.predicate = NSPredicate(format: "name = %#", name!)
do{
let fetchResults = try managedContext?.executeFetchRequest(fetchRequest)
let editingSubject = fetchResults![0] as! NSManagedObject
editingSubject.setValue(newName, forKey: "name")
editingSubject.setValue(newTeacher, forKey: "teacher")
editingSubject.setValue(newClassroom, forKey: "classroom")
do{
try managedContext?.save()
return true
}catch{
return false
}
}catch{
return false
}
}}
Thanks for any help

Resources