Sort Array of dictionary in Swift - ios

I am getting an array from response as below
items=[{
"displayName": "Adam Codo",
"postedTime": "2011-04-04T21:31:20.000Z",
"message" : "Hello Test Message"
},
{
"displayName": "Leena",
"postedTime": "2011-04-04T20:32:20.000Z",
"message" : " Start Hello Test Message"
},
{
"displayName": "Zohn",
"postedTime": "2011-04-03T22:47:20.000Z",
"message" : "Hi Leena"
},
{
"displayName": "Leena",
"postedTime": "2011-04-04T21:32:20.000Z",
"message" : " Start Hello Test Message"
},
{
"displayName": "Adam Codo",
"postedTime": "2011-04-04T22:13:10.000Z",
"message" : "Hello Test Message"
}]
I have so sort the array by the name & later by the time. so I need sorted array like below
items=[
{
"displayName": "Adam Codo",
"postedTime": "2011-04-04T22:13:10.000Z",
"message" : "Hello reply Test Message"
},
{
"displayName": "Adam Codo",
"postedTime": "2011-04-04T21:31:20.000Z",
"message" : "Hello Test Message"
},
{
"displayName": "Leena",
"postedTime": "2011-04-04T21:32:20.000Z",
"message" : " Start Hello Test Message"
},
{
"displayName": "Leena",
"postedTime": "2011-04-04T20:32:20.000Z",
"message" : " Start Hello Test Message"
},
{
"displayName": "Zohn",
"postedTime": "2011-04-03T22:47:20.000Z",
"message" : "Hi Leena"
}
]
Can anyone suggest me how to do this? Any idea would be great.

Do NOT use dictionaries
Build your own model instead and life will be easier.
Here's the model
struct Element {
let displayName: String
let postedTime: Date
let message: String
init?(dict:[String:String]) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
guard
let displayName = dict["displayName"],
let timeText = dict["postedTime"],
let postedTime = dateFormatter.date(from: timeText),
let message = dict["message"]
else { return nil }
self.displayName = displayName
self.postedTime = postedTime
self.message = message
}
}
Now let's make it Comparable
extension Element: Comparable {
static func <(lhs: Element, rhs: Element) -> Bool {
if lhs.displayName != rhs.displayName {
return lhs.displayName < rhs.displayName
}
return lhs.postedTime < rhs.postedTime
}
static func ==(lhs: Element, rhs: Element) -> Bool {
return lhs.displayName == rhs.displayName && lhs.postedTime < rhs.postedTime
}
}
Now given your array of dictionaries
let items = [
[
"displayName": "Adam Codo",
"postedTime": "2011-04-04T21:31:20.000Z",
"message" : "Hello Test Message"
],
[
"displayName": "Leena",
"postedTime": "2011-04-04T20:32:20.000Z",
"message" : " Start Hello Test Message"
],
[
"displayName": "Zohn",
"postedTime": "2011-04-03T22:47:20.000Z",
"message" : "Hi Leena"
],
[
"displayName": "Leena",
"postedTime": "2011-04-04T21:32:20.000Z",
"message" : " Start Hello Test Message"
],
[
"displayName": "Adam Codo",
"postedTime": "2011-04-04T22:13:10.000Z",
"message" : "Hello Test Message"
]
]
we can convert it to an array of Element(s) and finally sorting it
let sortedElms = items.flatMap(Element.init).sorted()
Result
[
Element(displayName: "Adam Codo", postedTime: 2011-04-04 21:31:20 +0000, message: "Hello Test Message"),
Element(displayName: "Adam Codo", postedTime: 2011-04-04 22:13:10 +0000, message: "Hello Test Message"),
Element(displayName: "Leena", postedTime: 2011-04-04 20:32:20 +0000, message: " Start Hello Test Message"),
Element(displayName: "Leena", postedTime: 2011-04-04 21:32:20 +0000, message: " Start Hello Test Message"),
Element(displayName: "Zohn", postedTime: 2011-04-03 22:47:20 +0000, message: "Hi Leena")
]

var sortedResults = items.sorted {
(dictOne, dictTwo) -> Bool in
if dictOne["displayName"]! != dictTwo["displayName"]! {
return dictOne["displayName"]! < dictTwo["displayName"]!
}
return dictOne["postedTime"]! < dictTwo["postedTime"]!
};

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]
initWithKey: #"displayName" ascending: YES];
NSArray *sortedArray = [_locations sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
NSArray *sortedLocations = [_locations sortedArrayUsingComparator: ^(NSDictionary *d1, NSDictionary *d2) {
ISO8601DateFormatter *formatter = [[ISO8601DateFormatter alloc] init];
NSDate *theDate1 = [formatter dateFromString:[d1 valueForKey:#"postedTime"]];
NSDate *theDate2 = [formatter dateFromString:[d2 valueForKey:#"postedTime"]];
return [theDate1 compare:theDate2];
}];
OR
NSArray *sortedLocations = [_locations sortedArrayUsingComparator: ^(NSDictionary *d1, NSDictionary *d2) {
ISO8601DateFormatter *formatter = [[ISO8601DateFormatter alloc] init];
NSDate *theDate1 = [formatter dateFromString:[d1 valueForKey:#"postedTime"]];
NSDate *theDate2 = [formatter dateFromString:[d2 valueForKey:#"postedTime"]];
NSString *name1 = [d1 valueForKey:#"displayName"];
NSString *name2 = [d2 valueForKey:#"displayName"];
if ([name1 compare:name2]) {
return [theDate1 compare:theDate2];
}
return NSOrderedDescending;
}];
But be awere I did not check it

Related

How to get the Current city in iOS

I want to send the city name to the server. I am getting latitude longitude using CLLocationManager. Then I use this link to do reverse geocoding.
https://maps.googleapis.com/maps/api/geocode/json?latlng=lati,longi&key=myApiKey
My problem is for different locations the number of address components are different. As an example, I am getting this array of address componeents for my current location.
"results": [
{
"address_components": [
{
"long_name": "ABC Rd",
"short_name": "ABC Rd",
"types": [
"route"
]
},
{
"long_name": "My City",
"short_name": "My City",
"types": [
"administrative_area_level_2",
"political"
]
},
{
"long_name": "My Province",
"short_name": "AB",
"types": [
"administrative_area_level_1",
"political"
]
},
{
"long_name": "My Country",
"short_name": "MC",
"types": [
"country",
"political"
]
}
],
For my client's location im getting this
results": [
{
"address_components": [
{
"long_name": "4",
"short_name": "4",
"types": [
"street_number"
]
},
{
"long_name": "some name",
"short_name": "some name",
"types": [
"route"
]
},
{
"long_name": "some name",
"short_name": "Some name",
"types": [
"political",
"sublocality",
"sublocality_level_2"
]
},
{
"long_name": "some name",
"short_name": "some name",
"types": [
"political",
"sublocality",
"sublocality_level_1"
]
},
{
"long_name": "city",
"short_name": "city",
"types": [
"locality",
"political"
]
},
{
"long_name": "some name",
"short_name": "Some name",
"types": [
"administrative_area_level_1",
"political"
]
},
{
"long_name": "Client country",
"short_name": "CC",
"types": [
"country",
"political"
]
},
{
"long_name": "12345",
"short_name": "12345",
"types": [
"postal_code"
]
}
],
How can I get the exact city name for different locations when the address components are different. First I tried to get it my component index number but since number of components are different I cant do that. Whats the correct way to do that? Please help me.
Thanks
UPDATE
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks objectAtIndex:0];
NSString *address = [NSString stringWithFormat:#"%# %#\n%# %#\n%#\n%#",
placemark.subThoroughfare, placemark.thoroughfare,
placemark.postalCode, placemark.subLocality,
placemark.subAdministrativeArea,
placemark.country];
// NSString *address=[self.placemark];
NSDictionary *dictAddress = [NSDictionary dictionaryWithDictionary:placemark.addressDictionary];
NSMutableDictionary *dictTxtData = [NSMutableDictionary dictionary];
NSLog(#"----LOCATION NAME----%#",[placemark.addressDictionary valueForKey:#"Name"]);
NSLog(#"-----STREET ADDRESS---%#",[placemark.addressDictionary valueForKey:#"Thoroughfare"]);
NSLog(#"-----CITY-----%#",[placemark.addressDictionary valueForKey:#"City"]);
strCountry=placemark.country;
NSLog(#"Address------%#",address);
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
Results I get
----LOCATION NAME----My Rd
-----STREET ADDRESS---My Rd
-----CITY-----(null)
Address------(null) My Rd
(null) (null)
(null)
My Country
This is how I call to location update
-(void)GetLocationData
{
if (self.locationManager == nil)
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
}
else
{
nil;
}
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
{
[self.locationManager requestWhenInUseAuthorization];
}
else
{
nil;
}
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;//kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
}
The json responses from Google API can contain different place marks depending upon the location. Using index is not the correct approach. You can find the city name in json components where type is locality. Below is the code snippet
NSDictionary *locationData = [[json objectForKey:#"results"] objectAtIndex:0];
NSArray* addressComponents= [locationData objectForKey:#"address_components"];
//Iterate each result of address components - find locality and country
NSString *cityName;
for (NSDictionary* address in addressComponents)
{
NSArray* addressType = [address objectForKey:#"types"];
NSString* firstType = [addressType objectAtIndex:0];
if([firstType isEqualToString:#"locality"])
cityName = [address objectForKey:#"long_name"];
}
or you can also use CLGeocoder API in iOS.
CLGeocoder *ceo = [[CLGeocoder alloc]init];
CLLocation *loc = [[CLLocation alloc]initWithLatitude:lat longitude:long];
[ceo reverseGeocodeLocation: loc completionHandler:
^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(#"placemark %#",placemark.locality); // Get the city name
}];
call setLocation() in viewdidload method
func setLocation()
{
// self.view.backgroundColor = UIColor.whiteColor()
self.edgesForExtendedLayout = .None
// Set bounds to inner-west Sydney Australia.
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
// print("dofo \(manager.location?.coordinate.latitude)")
// print(manager.location?.coordinate.longitude)
currentlat = (manager.location?.coordinate.latitude)!
cuurentlong = (manager.location?.coordinate.longitude)!
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: currentlat,
longitude: cuurentlong)
geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
// Place details
var placeMark: CLPlacemark!
placeMark = placemarks?[0]
// Address dictionary
print(placeMark.addressDictionary)
// Location name
if let locationName = placeMark.addressDictionary!["Name"] as? NSString {
print(locationName)
}
// Street address
if let street = placeMark.addressDictionary!["Thoroughfare"] as? NSString {
print(street)
}
// City
if let city = placeMark.addressDictionary!["City"] as? NSString {
print(city)
}
// Zip code
if let zip = placeMark.addressDictionary!["ZIP"] as? NSString {
print(zip)
}
// Country
if let country = placeMark.addressDictionary!["Country"] as? NSString {
print(country)
}
})
}

Parse JSON with Swift JSON

How to get Value Radio Name With Swift JSON
I wrote like this
let response = JSON["topradio"]["Data"]
before this i created model for values but am not able to pic values like radio_name
{
"topradio": {
"result": "success",
"Data": [
[
{
"radio_name": "Kantipur",
"rimage": "radio/1422960479145155755920731096211441695162.jpeg",
"status": "1",
"user_faverate": "false",
"popular_radio": "0",
"radio_id": "4"
}
]
[
{
"radio_name": "Kantipur",
"rimage": "radio/1422960479145155755920731096211441695162.jpeg",
"status": "1",
"user_faverate": "false",
"popular_radio": "0",
"radio_id": "4"
}
]
]
}
Thanks in Advance
You can iterate through your nested data Array this way.
let dataArray = JSON["topradio"]["Data"].array
for item in dataArray {
let itemArray = item.array
for subItem in itemArray {
if let name = subItem["radio_name"].string {
print(name)
}
}
}

Firebase Cloud Messing possible bug?

I am trying to send a push notification through FCM, but the response sent to the phone is weird and does not include aps.
I send:
{ "notification" : {
"title" : "this is title",
"body" : "this is body",
"sound" : "defadult"
},
"data": {
"score": "5x1",
"time": "15:10"
},
"time_to_live" : 3000,
"priority" : "high",
"content_available": true,
"to" : "<fcm access token>"
}
and I get the following on the phone:
%# [notification: {
body = "this is body";
e = 1;
sound = default;
sound2 = defadult;
title = "this is title";
}, collapse_key: <bundle-url>, score: 5x1, time: 15:10, from: 844316448558]
This had been working for a while but suddenly broke. Does anyone else experience this?

Swift 3 looping JSON data

I'm attempting to loop through a JSON array sending data to a struct.
Here's my code that uses SwiftyJSON to return a JSON object:
performAPICall() {
json in
if(json != nil){
print("Here is the JSON:")
print(json["content"]["clients"])
let clients = json["content"]["clients"]
for client in clients {
var thisClient = Client()
thisClient.id = client["id"].string
thisClient.desc = client["desc"].string
thisClient.name = client["name"].string
self.clientArray.append(thisClient)
}
self.tableView.reloadData()
} else {
print("Something went very wrong..,")
}
}
I'm not quite sure why I'm getting "has no subscript" errors on the three strings.
Any help appreciated, thanks.
EDIT: Here's a sample of the JSON
{
"content": {
"clients": [{
"group": "client",
"id": "group_8oefXvIRV4",
"name": "John Doe",
"desc": "John's group."
}, {
"group": "client",
"id": "group_hVqIc1eEsZ",
"name": "Demo Client One",
"desc": "Demo Client One's description! "
}, {
"group": "client",
"id": "group_Yb0vvlscci",
"name": "Demo Client Two",
"desc": "This is Demo Client Two's group"
}]
}
}
You should use array method. Thus, your line
let clients = json["content"]["clients"]
should use array (and unwrap it safely):
guard let clients = json["content"]["clients"].array else {
print("didn't find content/clients")
return
}
// proceed with `for` loop here

How to remove first and last { } in a NSString in iOS?

I want to remove first and last bracket from my NSString.
{
"Questions" : [
{
"title" : "This is my Question",
"question_id" : "123123123213",
"answers" : [
"correct answer 1",
"wrong answer 1",
"wrong answer 2",
"wrong answer 3"
],
"media_type" : "",
},
{
"title" : "This is my Question",
"question_id" : "2342342342342",
"answers" : [
"correct answer 1",
"wrong answer 1",
"wrong answer 2",
"wrong answer 3"
],
"media_type" : "",
}
]
}
I want to remove only first and last { } from the above NSString.
Make sure its not Dictionary. I have this in NSString.
UPDATE
The option is serializing:
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *dictJson = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:nil];
NSArray *arr = dictJson[#"Questions"];
for (NSDictionary *dict in arr)
{
NSLog(#"title ==%#",dict[#"title"]);
.....
}
UPDATE 2
But BE CAREFUL with your string. It's wrong. You have to check the commas after media_type:
{
"Questions" : [
{
"title" : "This is my Question",
"question_id" : "123123123213",
"answers" : [
"correct answer 1",
"wrong answer 1",
"wrong answer 2",
"wrong answer 3"
],
"media_type" : ""**,** //THIS
},
{
"title" : "This is my Question",
"question_id" : "2342342342342",
"answers" : [
"correct answer 1",
"wrong answer 1",
"wrong answer 2",
"wrong answer 3"
],
"media_type" : ""**,** //AND THIS
}
]
}
No commas have to go there.

Resources