accessing json content from dictionary - ios

I have a dictionary containing Json data. I am not able to handle the data inside it. I tried enumerating but keeps failing.
This is the data format I am getting back using NSLog:
2013-03-21 12:48:36.973 SaleItems[21009:c07] {
article = "Surface's other shoe is about to drop: the full Windows 8, Intel Core-driven Surface is headed to stores in just a few weeks.";
id = 2;
title = "Microsoft Surface Pro hits U.S. and Canada ";
}
2013-03-21 12:48:36.974 SaleItems[21009:c07] {
article = "Hit by growing demand for Samsung devices, the iPhone will lose smartphone market share for the current quarter, says a Citi analyst";
id = 3;
title = "iPhone to shed market share";
}
2013-03-21 12:48:36.974 SaleItems[21009:c07] {
article = "The carrier says it plans to buy wireless spectrum and network assets from Atlantic Tele-Network, aka Alltel, in an effort to boost its spectrum coffers.";
id = 4;
title = "AT&T spends $780 million ";
}
I know from the looks of it that I am getting back a dictionary of arrays. How can I access the arrays and elements inside them?

It looks like you have key as article, id and title, simply access the object in loop as:
*I am assuming that you have a Class called SalesItem and the above log are from each object of that
for(SalesItem *object in SalesItem){
NSLog(#"Article : %#",object[#"article"]);
NSLog(#"Id : %#",object[#"id"]);
NSLog(#"Title : %#",object[#"title"]);
}

Related

Stream data (Artist / Title) not displaying in AVPlayerItemTrack array in xcode

I have the following code which, when used on most (Shoutcast) streaming servers, returns the artist/song metadata, but on a particular server it is not working and is simply displaying the letter 't'!
As NSLog isn't currently working for me (despite all kinds of changes, I can't get it to work (Xcode 9.2)), I'm slightly in the dark.
- (void)FetchMeta
{
for (AVPlayerItemTrack *item in player.currentItem.tracks)
{
if ([item.assetTrack.mediaType isEqual:AVMediaTypeAudio])
{
NSArray *meta = [playerItem timedMetadata];
for (AVMetadataItem *metaItem in meta)
{
NSString *source = metaItem.stringValue;
if(![source isEqualToString:self.songInfo.text])
{
self.songInfo.text = [source stringByAppendingString:#" "];
//self.songInfo.text = #"Test";
[self LoadArtistImage];
}
NSLog(#"meta %#\n%#",source,metaItem.extraAttributes);
}
}
}
}
I know I'm in the right part of the code, because if I uncomment the //self.songInfo.text = #"Test"; line, I see it on the display where the song metadata should appear, but have been on this for 3 hours solid and can't get it to display the metadata and not having NSLog really isn't helping.
UPDATE : I have been able to interrogate the servers and can see the difference, but I still no not know how to tell the code to look in correct field... My understanding is that the data is being put into an array (I think) but it is taking the wrong field. Maybe it is always just taking the last field? TO be clear, I'm looking for it to take the 'StreamTitle' field.
Working server response:
Input #0, mp3, from 'http://server:port':
Metadata:
icy-notice1 : <BR>This stream requires Winamp<BR>
icy-notice2 : SHOUTcast DNAS/posix(linux x86) v2.5.1.724<BR>
icy-name : Station Name
icy-genre : 80s, Pop
icy-br : 128
icy-sr : 44100
icy-url : http://website.com
icy-pub : 1
StreamTitle : Rod Stewart - Lost In You
Non working server response:
Input #0, mp3, from 'http://server:port/':
Metadata:
icy-notice1 : <BR>This stream requires Winamp<BR>
icy-notice2 : SHOUTcast Distributed Network Audio Server/Linux v1.9.8<BR>
icy-name : Station Name
icy-genre : Various
icy-url : www.website.com
icy-pub : 1
icy-br : 128
StreamTitle : Theory of a Deadman - Rx
StreamUrl : t
To further clarify. The 'working server' output works correctly displaying the 'StreamTitle' field using the code displayed, the non working server displays the last field 'StreamUrl' which is not the desired field.
Any pointers?
Many thanks.
As #Larme says your loop will essentially set your text field to the value of each item in turn, so the value of the last item "wins".
You have to only set your text field if the current item in your loop is the stream title, something like that:
for (AVMetadataItem *metaItem in meta)
{
if([metaItem.key isEqualTo: AVMetadataIcyMetadataKeyStreamTitle])
{
self.songInfo.text = metaItem.stringValue;
}
}

Compare String and Array in iOS

I have hired a iOS developer to create an app which will be backed by the REST API. Now I'm stuck with a problem with one output.
There are Public and Private Groups, if group is Private, the API will return following in json format:
privacy":{"value":"1"},
and if the group is Public, the API will return following in json format:
"privacy":[]
The iOS developer says that this output is incorrect while on the other hand API developer believe this is correct output. Can anyone please tell me is this output correct to be used in iOS app or it's not correct?
iOS Developer days he can't compare String and Array.
Yes it's correct, given there is no such thing as incorrect with JSON, as there is no schema to conform to. As long as it's legal, it's OK.
The iOS developer can test the type of the "privacy" value after it's been deserialised:
id value = jsonDict[#"privacy"];
if ([value isKindOfClass:[NSDictionary class]]) {
// Value is dictionary
NSDictionary *dictValue = (NSDictionary *)value;
NSString *number = dictValue[#"value"]; // This should be a number, not a string!
} else if ([value isKindOfClass:[NSArray class]]) {
// Value is array
} else {
// Value is illegal. Report error.
}
I will say that it should be:
{"value":1}
as 1 is a number, not a string.
Yes, iOS developer can check response.
But there should be consistency in JSON response.
It is not correct way that one API give response in array and other in dictionary.
It should be either array or string that would be preferable for iOS developer.
Output should be:
{
"privacy":[{"value":1}]
}
For validating JSON response you can use http://jsonlint.com/
The API is designed incorrectly, as it provides various data types for the privacy key (and no schema defines how this should behave). Once it's a dictionary, once it's an empty array.
I'd suggest using an array in any case.
Private:
privacy : [ {"value" : true} ]
Public:
privacy : []
However, it's possible to concatenate array to string and then compare with string (using let stringRepresentation = ",".join(array))

iOS Convert phone number to international format

In my iOS app I have to convert a phone number (taken in the contacts) and convert it in international format (to send SMS automatically with an extern library). I saw libPhoneNumber but the problem is that we have to enter the country code, and the app have to work in all (almost) countries, so I don't know what is the user's country.
Here is how the library works :
let phoneUtil = NBPhoneNumberUtil()
let phoneNumberConverted = try phoneUtil.parse("0665268242", defaultRegion: "FR") // So I don't know the country of the user here
print(try? phoneUtil.format(phoneNumberConverted, numberFormat: NBEPhoneNumberFormat.INTERNATIONAL))
formattedPhoneNumberSubstring takes a partial phone number string and formats it as the beginning of a properly formatted international number, e.g. "16463" turns to "+1 646-3".
NSString *formattedPhoneNumberSubstring(NSString *phoneNumber) {
NBPhoneNumberUtil *phoneUtil = [NBPhoneNumberUtil sharedInstance];
phoneNumber = [phoneUtil normalizeDigitsOnly:phoneNumber];
NSString *nationalNumber;
NSNumber *countryCode = [phoneUtil extractCountryCode:phoneNumber nationalNumber:&nationalNumber];
if ([countryCode isEqualToNumber:#0])
return phoneNumber;
NSString *regionCode = [[phoneUtil regionCodeFromCountryCode:countryCode] objectAtIndex:0];
NSString *paddedNationalNumber = [nationalNumber stringByPaddingToLength:15 withString:#"0" startingAtIndex:0];
NSString *formatted;
NSString *formattedSubstr;
for (int i=0; i < paddedNationalNumber.length; i++) {
NSError *error = nil;
formattedSubstr = [phoneUtil format:[phoneUtil parse:[paddedNationalNumber substringToIndex:i] defaultRegion:regionCode error:&error]
numberFormat:NBEPhoneNumberFormatINTERNATIONAL error:&error];
if (getExtraCharacters(formattedSubstr) > getExtraCharacters(formatted)) // extra characters means more formatted
formatted = formattedSubstr;
}
// Preparing the buffer for phoneNumber
unichar phoneNumberBuffer[phoneNumber.length+1];
[phoneNumber getCharacters:phoneNumberBuffer range:NSMakeRange(0, phoneNumber.length)];
// Preparing the buffer for formatted
unichar formattedBuffer[formatted.length+1];
[formatted getCharacters:formattedBuffer range:NSMakeRange(0, formatted.length)];
int j=0;
for(int i = 0; i < phoneNumber.length && j < formatted.length; i++) {
while(formattedBuffer[j] != phoneNumberBuffer[i]) j++;
j++;
}
return [formatted substringToIndex:j];
}
You can get the region using either the users locale or the users geo position.
See stackoverflow question get device location country code for more details.
If you don’t know the country code of a phone number, you can’t generate the international format of it.
You could try using the location of the phone or its region settings to guess the country code, but it won’t be reliable. For example, my phone number is Spanish, I’m currently in Italy and my region is set to New Zealand. My contact list contains numbers from all over the world, and if they weren’t entered in international format there would be no way to guess what country code to use for each number.
If you absolutely have to guess, the best approach might be to think about how the phone would interpret the numbers in the contact list itself. This would require you to determine the country code of the phone’s SIM card. See this answer to a related question for a way of doing that, or here’s some Swift code I’ve used:
let networkInfo = CTTelephonyNetworkInfo()
if let carrier = networkInfo.subscriberCellularProvider {
NSLog("Carrier: \(carrier.carrierName)")
NSLog("ISO: \(carrier.isoCountryCode)")
NSLog("MCC: \(carrier.mobileCountryCode)")
NSLog("MNC: \(carrier.mobileNetworkCode)")
}
The ISO country code can be used to look up a country code for dialling; an example table is in the answer linked above.

if statements and stringWithFormat

I need to know if there is a way to use if statements to display certain nsstrings, depending on whether or not that NSString contains any data.
I have an nsstringcalled visitorInfo.
The string uses data from other strings (i.e. which operating system the user is running) and displays that info. Here is an example of what I'm talking about:
NSString *visitorInfo = [NSString stringWithFormat:#"INFO\n\nVisitor Location\n%#\n\nVisitor Blood Type\n\%#", _visitor.location, _visitor.bloodType];
And it would display like this:
INFO
Location
Miami, FL
Blood Type
O positive
However, I have several pieces of data that only load if the user chooses to do so. i.e their email address.
This section of code below would do what I want, but my visitorInfo string contains tons of different strings, and if I use this code below, then it won't load any of them if the user chooses not to submit his blood type.
if ([self.visitor.bloodType length] > 0) {
NSString *visitorInfo = [NSString stringWithFormat:#"INFO\n\nVisitor Location\n%#\n\nVisitor Blood Type\n\%#", _visitor.location, _visitor.bloodType];
}
So basically if their is data stored in bloodType then i went that code to run, but if there isn't any data I only want it to skip over bloodType, and finish displaying the rest of the data.
Let me know if you have any more questions
Additional details. I'm using an NSString for a specific reason, which is why I'm not using a dictionary.
Just build up the string as needed using NSMutableString:
NSMutableString *visitorInfo = [NSMutableString stringWithFormat:#"INFO\n\nVisitor Location\n%#, _visitor.location];
if ([self.visitor.bloodType length] > 0) {
[visitorInfo appendFormat:#"\n\nVisitor Blood Type\n\%#", _visitor.bloodType];
}
You can check if a string has any data in it by using the following
if([_visitor.location length]<1){
//This means there's no data and is a better way of checking, rather than isEqualToString:#"".
}else{
//there is some date here
}
** EDIT - (just re-reading your question, sorry this answer is dependant on _visitor.location being a string in the first place)*
I hope this helps
Try this -
NSString *str = #"INFO";
if (_visitor.location) {
str = [NSString stringWithFormat:#"\n\nVisitor Location\n%#",_visitor.location];
}
if (_visitor.bloodType) {
str = [NSString stringWithFormat:#"\n\nVisitor Blood Type\n\%#",_visitor.bloodType];
}

Formatting & Manipulation database data for display in tableview

I am working on an application to display user information stored in a database in an iOS app in a table view. Currently i am logging all information from the server to the console (in the debug area) using
NSLog(#"user information is as follows: %#", JSON);
Which provides output as such:
{ email = “andrew.smith19381223#gmail.com”;
“first_name” = Andrew;
“Last_name” = Smith
id = 12
user_info= (
{
"Room" = "Lab 2";
DayNumber = 1;
lesson = 2;
id = 12;
Instructor = "MR BEERRY";
Group_No = 7;
},
{
"class_room" = "S GEO";
DayNumber = 1;
lesson = 2;
id = 12;
teacher = "Mr RING";
Group_No = 7;
},
...
I would like to use this information in table view columns and as parameters (for eg. the day no.) for the tableview.How should i store/format this information in my iOS application so it can be used for a tableview.I have been googleing for a while without luck :(
Use a JSON parser (e.g. NSJSONSerialization) in order to parse the JSON text and create a representation. The generic representation is a hierarchy of Foundation objects. In your case, the root element is a JSON Object which maps to a NSDictionary in the representation. That dictionary contains the keys #"email", #"first_name", #"Last_name", #"id", #"user_info", etc. You can access the corresponding value for a key with the method -objectForKey: which you should be familiar with.
The corresponding object for key #"user_info" is a NSArray, whose elements are objects of kind NSDictionary.
And so force.
Since the JSON is a dynamic data structure you need some knowledge in the application what that JSON actually shall be and what you expect when you receive that. That is, you may expect a certain structure and keys and certain values. In order to make your live easier, you may use that representation to initialize your "custom model" - which has properties and behavior as you require.
Once you have your model, display it as usual in a UITable view.

Resources