How read Group By of core data - swift - swift

I have bellow query:
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Cohorts")
fetchRequest.propertiesToGroupBy = ["ctype", "is_selected"]
fetchRequest.propertiesToFetch = ["ctype", "is_selected"]
fetchRequest.resultType = .dictionaryResultType
let results = try self.privateManagedObjectContext.fetch(fetchRequest) as Array
And bellow is my result value from above query:
(
{
ctype = offline;
"is_selected" = 0;
},
{
ctype = online;
"is_selected" = 0;
}
)
How can I read results or how can I insert above result to custom model like bellow?
struct TEST
{
var ctype : String
var is_selected : Int
}

Add one line
let testArray = results.map{TEST(ctype: $0["ctype"] as! String, is_selected: $0["is_selected"] as! Int)}

Related

Swift 4 - CodableFirebase and nested child with UID

I am trying to use CodableFirebase to parse a snapshot.
My Json is like this :
snapshot.value = Optional({
Box = {
Outbox = {
"-LpdzdzdzdzdDs7" = {
DateInvoice = "2019-09-23 10:41:20 +0000";
TrailOrHike = Hike;
Number_of_child = 2;
Children = {
0VZrgdYvV4hyhhyhhy4tyElASvR83 = {
DateVenue = "2019-09-23 10:43:44 +0000";
Age = 3;
"Avatar" = "gs://oooo.appspot.com/Avatar/0V3R4tyElASvR83.png";
};
wQpyIhyhyhyhyh1CI6YBfc3yppX2 = {
"Avatar" = "http://graph.facebook.com/00000/picture?type=large&height=200&width=200";
};
};
In my Outbox, I can have UID (of families)
And in each UID, I can have 0,1 or x children, with data inside.
I would like to parse it correctly but I don't manage to do it with dynamic UID (like -LpdzdzdzdzdDs7), and inside this dynamic UID ,there is more data to parse (Age,DateVenue,Avatar)..
I have no problem to parse other data, but when it's nested I am lost .
My Codable for the rest is simple :
struct CampProfile: Codable {
struct Family : Codable {
let DateVenue : String?
enum CodingKeys : String, CodingKey {
case DateVenue
}
}
let Camp_Name: String
let Camp_Adress: String
}
let model = try FirebaseDecoder().decode(CampProfile.self, from: value)
print(model)
let model2 = try FirebaseDecoder().decode(CampProfile.Family.self, from: value)
print(model2) . //NOTWORKING

How to sort JSON Data in Array in swift 4

I have JSON array like this
var json = NSArray() // array with json objects
//print json >>
json = (
{
Name = "Alen";
Score = 500;
},
{
Name = "John";
Score = 0;
},
{
Name = "Mark";
Score = 2000;
},
{
Name = "Steve";
Score = 300;
},
{
Name = "Ricky";
Score = 900;
}
)
and i can access its objects as
(json[0] as! NSDictionary).object(forKey: "Name")
(json[0] as! NSDictionary).object(forKey: "Score")
I want to sort this JSON array according to scores.
I found the answers like
let sortedArray = json.sorted(by: { $0.0 < $1.0 })
which gives error
Value of type 'Any' has no member '0'
Then I tried this
let sortedArray = (json as! NSDictionary).sorted {(aDic, bDic) -> Bool in
return aDic.key < bDic.key
}
It gave error
Binary operator '<' cannot be applied to two 'Any' operands
Can you please guide me to sort the array according to score in swift 4?
That's a very good example why you are strongly discouraged from using NSArray and NSDictionary in Swift.
Both collection types don't provide type information so everything is treated as Any. Most of the shared generic API of the Swift Standard library cannot be used with Any so you are not able to take advantage of the powerful generic functions unless you add a lot of ugly type casts.
If all values are String declare your array as
var json = [[String:String]]()
Then you can sort the array with
let sortedArray = json.sorted { $0["Score"]! < $1["Score"]! }
The most recommended solution is to decode the JSON directly into a custom struct
struct Player : Decodable {
let name : String
let score : String
private enum CodingKeys : String, CodingKey { case name = "Name", score = "Score" }
}
Then you get rid of all type casting and you can sort by the property name
var players = [Player]()
let jsonString = """
[{"Name" : "Alen", "Score" : "500"},
{"Name" : "John", "Score" : "0"},
{"Name" : "Mark", "Score" : "2000"},
{"Name" : "Steve", "Score" : "300"},
{"Name" : "Ricky", "Score" : "900"}]
"""
let data = Data(jsonString.utf8)
do {
players = try JSONDecoder().decode([Player].self, from: data)
let sortedPlayers = players.sorted{ $0.score.compare($1.score, options: .numeric) == .orderedAscending }
print(sortedPlayers)
} catch { print(error) }
Edit:
To load the JSON use an asynchronous way (URLSession)
Never load data from a remote URL with synchronous Data(contentsOf.
var players = [Player]()
let jsonUrl = URL(string: "url.json")!
let task = URLSession.shared.dataTask(with : url) { [unowned self] (data, _, error) in
if let error = error { print(error); return }
do {
players = try JSONDecoder().decode([Player].self, from: data!).sorted{ $0.score < $1.score }
DispatchQueue.main.async { // reload the table view if necessary
self.tableView.reloadData()
}
} catch { print(error) }
}
task.resume()
After parsing your json, you can sort your score array like this
var scoreArray = ["500", "0", "2000", "300", "900"]
array.sort { $0.compare($1, options: .numeric) == .orderedAscending }
I did something like this before
First I created two arrays of dictionary
var jsonArray = [(name:String, score:String)]()
var sortedscoreArray:[(name: String, score: String)] = []
and in getting json data you can create for loop
for I in 0..< jsonData.count{
Let jsonInfo = jsonData[i]
jsonArray.append((name: jsonInfo[“Name”].string!, score: jsonInfo[“Score"].string!))
}
and after you fill the json array pass it to sortedArray
sortedscoreArray = jsonArray.sorted(by: { $0.score < $1.score })
If array contains dictionary then you can use this code for sorting:
let sortedArray = json.sort { $0["Score"] as! Int < $1["Score"] as! Int }
print(sortedArray)
and if you are using bean class then you can use dot(.) properties for sorting:
let sortedArray = json.sort { $0.Score < $1.Score }
print(sortedArray)
let sortedResults = self.json?.sorted(by: {$0.name ?? EMPTY_STRING < $1.name ?? EMPTY_STRING }) ?? []

Alamofire returning error

I am using below code to get json data from server and it is returning error.
code :
func getPosts(page : Int, count : Int,completionHandler: (responseObject: ResponseModel) -> ()){
let header = ["Content-Type": "application/json"]
let responseModel = ResponseModel()
var posts = [StoryModel]()
var comments = [CommentModel]()
var customFields = [CustomFieldModel]()
let medium = ImageTypeModel()
let high = ImageTypeModel()
var postCount = [String]()
var categories = [CategoryModel]()
manager!.request(.GET, "http://www.anonews.co?json=get_recent_posts", parameters: ["page": page,"count" :count],headers: header)
.responseJSON { response in
switch response.result {
case .Success:
if let value = response.result.value {
let json = JSON(value)
print(json)
responseModel.status = json["status"].stringValue
responseModel.count = json["count"].intValue
responseModel.count_total = json["count_total"].intValue
responseModel.pages = json["pages"].intValue
for item in json["posts"].arrayValue {
let storymodel = StoryModel();
storymodel.comment_count = item["comment_count"].stringValue
storymodel.content = item["content"].stringValue
storymodel.excerpt = item["excerpt"].stringValue
storymodel.id = item["id"].intValue
storymodel.imageUrl = item["url"].stringValue
storymodel.title_plain = item["title_plain"].stringValue
storymodel.thumbnail = item["thumbnail"].stringValue
medium.url = item["thumbnail_images"]["medium_large"]["url"].stringValue
high.url = item["thumbnail_images"]["mvp-medium-thumb"]["url"].stringValue
storymodel.medium_large = medium
storymodel.mvp_medium_thumb = high
for category in json["posts"]["categories"].arrayValue {
let categoryModel = CategoryModel()
categoryModel.id = category["id"].intValue
categoryModel.title = category["title"].stringValue
categories.append(categoryModel)
}
storymodel.categories = categories
for commentobject in json["posts"]["comments"].arrayValue {
let comment = CommentModel()
comment.content = commentobject["content"].stringValue
comment.name = commentobject["name"].stringValue
comments.append(comment)
}
storymodel.comments = comments
for customFieldObject in json["posts"]["custom_fields"].arrayValue {
let customField = CustomFieldModel()
for post_count in customFieldObject["post_views_count"].arrayValue {
let count = post_count["post_views_count"].stringValue
postCount.append(count)
}
customField.post_views_count = postCount
customFields.append(customField)
}
storymodel.custom_fields = customFields
posts.append(storymodel)
}
responseModel.posts = posts
completionHandler(responseObject: responseModel)
}
case .Failure(let error):
print(error)
}
}
}
Here is the error message:
0
Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}
Any one know what is the issue in my code?
I see you use .GET request, and transfer parameter in body. So the result will become Failure.

Problems linking objects in realm swift

I am having problems linking objects in realm. I read the question and answer titled "Nested objects in realm" and tried the answer suggested but it did not work for me.
Here are my object classes:
import Foundation
import RealmSwift
class Job: Object {
dynamic var id = NSUUID().UUIDString
dynamic var name = ""
dynamic var address = ""
dynamic var phone = ""
dynamic var email = ""
dynamic var notes = ""
dynamic var material = 0.0
dynamic var edge = 0.0
dynamic var splash = 0.0
dynamic var discount = 0.0
dynamic var trip = 0.0
let rooms = List<Room>()
override static func primaryKey() -> String {
return "id"
}
}
import Foundation
import RealmSwift
class Room: Object {
dynamic var id = NSUUID().UUIDString
dynamic var name = ""
dynamic var material = 0.0
dynamic var edge = 0.0
dynamic var splash = 0.0
dynamic var sinkType = ""
dynamic var sinkModel = ""
dynamic var numberOfSinks = 0
dynamic var faucet = ""
dynamic var rangeType = ""
dynamic var notes = ""
dynamic var jobs: Job?
let countertops = List<Countertop>()
//var linksToJob: [Job] {
// return linkingObjects(Job.self, forProperty: "rooms")
//}
override static func primaryKey() -> String {
return "id"
}
}
import Foundation
import RealmSwift
class Countertop: Object {
dynamic var id = NSUUID().UUIDString
dynamic var depth = 0.0
dynamic var width = 0.0
dynamic var cabDescription = ""
dynamic var sqFt = 0.0
dynamic var room: Room?
//var linkToRoom: [Room] {
// return linkingObjects(Room.self, forProperty: "countertops")
//}
override static func primaryKey() -> String {
return "id"
}
}
Here are the functions I use to save the data:
#IBAction func saveButton() {
jobs.name = nameTF.text!
jobs.address = addressTF.text!
jobs.phone = phoneTF.text!
jobs.email = emailTF.text!
jobs.notes = notesTV.text!
jobs.discount = Double(discountTF.text!)!
jobs.material = Double(materialTF.text!)!
jobs.edge = Double(edgeTF.text!)!
jobs.splash = Double(splashTF.text!)!
jobs.trip = Double(tripTF.text!)!
do {
try! realm.write {
realm.add(jobs)
}
}
print(jobs)
// print(Realm.Configuration.defaultConfiguration.path!)
}
func saveData(){
rooms.name = nameTF.text!
rooms.material = Double(materialTF.text!)!
rooms.edge = Double(edgeTF.text!)!
rooms.splash = Double(splashTF.text!)!
rooms.notes = notesTV.text
rooms.sinkType = sinkTypeTF.text!
rooms.sinkModel = sinkModelTF.text!
rooms.numberOfSinks = Int(numberSinksTF.text!)!
rooms.faucet = faucetTF.text!
rooms.rangeType = rangeTF.text!
rooms.jobs?.id = keyValueLabel.text!
//rooms.linksToJob
do {
try! realm.write {
realm.add(rooms)
}
}
print(rooms)
}
and:
#IBAction func addNextButton(sender: AnyObject) {
// self.realm.beginWrite()
let realm = try! Realm()
if widthTF.text != "" {
Calculations.depth = Double(depthTF.text!)!
Calculations.width = Double(widthTF.text!)!
let depthAdded = depthTF.text
cabinetDepth.append(Double(depthAdded!)!)
let widthAdded = widthTF.text
cabinetWidth.append(Double(widthAdded!)!)
let descriptionAdded = pickerLabel.text
cabinetDescription.append(descriptionAdded!)
let runningTotal = Calculations.squareFeet()
squareFeetToBeAdded.append(runningTotal)
let sum = squareFeetToBeAdded.reduce(0,combine: {$0 + $1})
let roundedSqFt = Double(round(sum * 10) / 10)
sqFtLabel.text = "\(roundedSqFt)"
countertops.depth = Double(depthTF.text!)!
countertops.width = Double(widthTF.text!)!
countertops.cabDescription = pickerLabel.text!
countertops.sqFt = Double(sqFtLabel.text!)!
//countertops.linkToRoom
do {
try realm.write {
realm.add(countertops)
}
print(countertops)
} catch {
print("an error occurred")
}
widthTF.text = ""
numberTable.reloadData()
widthTF.becomeFirstResponder()
}
}
When I save the data and print the results here is what I get:
Job {
id = 00F95F55-54D8-426E-B483-C990A4171002;
name = Ken;
address = Address;
phone = phone;
email = email;
notes = Notes :;
material = 8;
edge = 0;
splash = 4;
discount = 1;
trip = 0;
rooms = RLMArray <0x7ffef9df29c0> (
);
}
Room {
id = 7D3F86B9-FCD7-4CB7-AD6E-9B8141A7390C;
name = Kitchen;
material = 9;
edge = 0;
splash = 4;
sinkType = Undermount Kitchen;
sinkModel = 50/50 Stainless Steel;
numberOfSinks = 1;
faucet = Single Hole;
rangeType = Free Standing Range;
notes = Notes:;
jobs = (null);
countertops = RLMArray <0x7ffef9df3720> (
);
}
Countertop {
id = 992B8BAE-392F-4513-85DC-CBA191D2AE08;
depth = 25.5;
width = 65;
cabDescription = Cabinet;
sqFt = 11.5;
room = (null);
}
As you can see the links return null.
Please tell me what I am doing wrong here.
Note: I comment out the linkingObjects in the models because it caused a crash. I'm not sure why.
You should use references to existing realm objects when adding them. So rather than this:
func saveData(){
rooms.name = nameTF.text!
rooms.material = Double(materialTF.text!)!
rooms.edge = Double(edgeTF.text!)!
rooms.splash = Double(splashTF.text!)!
rooms.notes = notesTV.text
rooms.sinkType = sinkTypeTF.text!
rooms.sinkModel = sinkModelTF.text!
rooms.numberOfSinks = Int(numberSinksTF.text!)!
rooms.faucet = faucetTF.text!
rooms.rangeType = rangeTF.text!
rooms.jobs?.id = keyValueLabel.text!
//rooms.linksToJob
do {
try! realm.write {
realm.add(rooms)
}
}
print(rooms)
}
You would use something like this:
let realm = try! Realm()
let room = realm.create(Room.self)
room.name = nameTF.text!
room.material = Double(materialTF.text!)!
...
let job = realm.create(Job.self)
job.name = "My job name"
...
room.job = job
Since it looks like you're entering these on separate screens, you will add a room, then you want to add a job:
if let existingJob = realm.objects(Job).filter("name == '\(jobNameToLookup)'").first {
room.job = existingJob
}
For a list, just do room.countertops.append(newCountetop), where newCountertop is the result of realm.create
Because you add each objects into the Realm individually without linking. If you'd like to link the objects, you should add the objects to the List properties, such like rooms and countertops. Also for to-one relationships, you should assign the object to the property.
So you need write the code something like the following:
...
rooms.faucet = faucetTF.text!
rooms.rangeType = rangeTF.text!
...
rooms.countertops.append(countertops)
...
jobs.rooms.append(rooms)
And,
...
countertops.rooms = rooms
...
rooms.jobs = jobs
For more details, see also the documents:
Thanks to Austin who got me on the right track. Here is the code that finally did it.
#IBAction func roomSaveNextBtnPushed(_ sender: UIButton) {
let room = Room()
room.roomName = roomTF.text!
room.material = materialTF.text!
room.edge = edgeTF.text!
room.job = realm.objects(Job.self).last
try! realm.write {
realm.add(room)
print(room)
}
}
The link is made in the ' realm.object(Job.self).last ' line of code. This adds a room to a job as expected.
The suggestion in Austin's example ' let room = realm.create(Room.self) ' caused an error, and the project would not compile.
I am using Xcode 8 with Swift 3 and Realm-swift 1.1.0
Thanks again to those who offered help.

two dimensional array fill up with code and description empty in swift

I have defined my array in swift like
let cList = [[String]]()
now i want to fill the array with while getting response country code and country description.
So i can get it at the time of submit the page.
I am fetching my response below:
if let results = jsonResult["country"] as? NSArray
{
for country in results { {
let couCode: String? = country["couCode"] as? String
let couDescription: String? = country["couDescription"] as? String
println(couCode,couDescription)
self.countryList.append(couDescription!)
}
}
Now from above code how would i fill the two dimension array?
Is this what you're looking for?
var cList = [[String]]()
cList.append(["code1", "description1"])
cList.append(["code2", "description2"])
cList.append(["code3", "description3"])
cList.append(["code4", "description4"])
let towCode:String = "code4"
let towDescription:String = "description4"
for var i:Int = 0; i < cList.count; i++
{
if towCode == cList[i][0]
{
println("towCode found in cList at location \(i)")
println("towDescription at this location = \(cList[i][1])")
break;
}
}
for var i:Int = 0; i < cList.count; i++
{
if towDescription == cList[i][1]
{
println("towDescription found in cList at location \(i)")
println("towCode found at this location = \(cList[i][0])")
break;
}
}
Result:
towCode found in cList at location 3
towDescription at this location = description4
towDescription found in cList at location 3
towCode found at this location = code4
If you want to find multiple hits in cList, delete the break statements.
If I understand your situation, for a two dimensional array:
var cList = [[String]]()
cList.append(["String1", "String2"])
cList.append(["String3", "String4"])
println("cList = \(cList)")
println("cList[0][0] = \(cList[0][0])")
println("cList[0][1] = \(cList[0][1])")
Result:
cList = [[String1, String2], [String3, String4]]
cList[0][0] = String1
cList[0][1] = String2
or:
var cList = [[String]]()
cList.append(["String1", "String2", "String5"])
cList.append(["String3", "String4", "String6"])
println("cList = \(cList)")
println("cList[0][0] = \(cList[0][0])")
println("cList[0][1] = \(cList[0][1])")
println("cList[0][2] = \(cList[0][2])")
Result:
cList = [[String1, String2, String5], [String3, String4, String6]]
cList[0][0] = String1
cList[0][1] = String2
cList[0][2] = String5