When attempting to save a PFObject, I was receiving the error "Error: object not found for update (Code: 101, Version: 1.2.15)" (logged automatically), and the localized description was logging: The operation couldn’t be completed. (Parse error 101.)
I eventually isolated the problem: the NSDictionary I was assigning to one of the fields on the PFObject had quotation marks around key names; turns out these are added automatically by the NSDictionary class when a key name contains nonalphanumeric characters.
Here's an example of a (logged) PFObject whose save was giving an error:
"<PlaybackPositionTracker:MKXTjOXg07:(null)> {\n ACL = \"<PFACL: 0xc1e80f0>\";\n aclRead = (\n \"\"\n );\n aclWrite = (\n \"\"\n );\n deletedAt = \"<null>\";\n nowPlaying = \"<null>\";\n playbackPositionDictionary = {\n \"http://podcastdownload.npr.org/anon.npr-podcasts/podcast/35/290491304/npr_290491304.mp3\" = 0;\n };\n}"
I suppose Parse interprets quotation marks to indicate a link to another Parse object or something (or else I'm at a loss to explain why this gives the "object not found" error).
How can I use a url string as a key in a dictionary that is assigned to a field on a PFObject? I could remove all nonalphanumeric characters from the string, but that would be a messy solution. What other options might there be? Thank you.
Is there a reason you can't store and retrieve them separately?
NSString * url = #"http://podcastdownload.npr.org/anon.npr-podcasts/podcast/35/290491304/npr_290491304.mp3";
CGFloat currentPlaybackPosition = 0.0; // position in seconds
NSMutableDictionary * playbackPositionDictionary = [NSMutableDictionary new];
playbackPositionDictionary[#"URL"] = url;
playbackPositionDictionary[#"Seconds"] = [NSNumber numberWithFloat:currentPlaybackPosition];
PFObject * ob = [PFObject objectWithClassName:#"TrialClass"];
ob[#"playbackPositionDictionary"] = playbackPositionDictionary;
[ob saveInBackground];
// Retrieve
NSDictionary * retrievedPlaybackPositionDictionary = ob[#"playbackPositionDictionary"];
NSString * urlForPlaybackPosition = retrievedPlaybackPositionDictionary[#"URL"];
CGFloat playbackPositionInSeconds = [retrievedPlaybackPositionDictionary[#"Seconds"]floatValue];
NSLog(#"Start playing: %# starting at: %#", urlForPlaybackPosition, playbackPositionInSeconds);
The only solutions I can think of involve converting the URL to a more accessible key. Would this work as an alternative solution?
I'm not sure if this is improved, but if you want to store these dictionaries on Parse, perhaps converting them to data strings is another work around:
Declare Methods:
- (NSString *) hexStringFromDictionary:(NSDictionary *)dict {
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict
options:0
error:&error];
return [jsonData description];
}
- (NSDictionary *) dictionaryFromHexString:(NSString *)string {
string = [string lowercaseString];
NSMutableData *data= [NSMutableData new];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
int i = 0;
int length = string.length;
while (i < length-1) {
char c = [string characterAtIndex:i++];
if (c < '0' || (c > '9' && c < 'a') || c > 'f')
continue;
byte_chars[0] = c;
byte_chars[1] = [string characterAtIndex:i++];
whole_byte = strtol(byte_chars, NULL, 16);
[data appendBytes:&whole_byte length:1];
}
return [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
}
Conversion From HexString Modified From HERE!
Create Your Dictionary:
NSString * url = #"http://podcastdownload.npr.org/anon.npr-podcasts/podcast/35/290491304/npr_290491304.mp3";
CGFloat currentPlaybackPosition = 0.0; // position in seconds
NSMutableDictionary * playbackPositionDictionary = [NSMutableDictionary new];
playbackPositionDictionary[url] = [NSNumber numberWithFloat:currentPlaybackPosition];
Save To PFObject:
PFObject * ob = [PFObject objectWithClassName:#"ParseClass"];
NSString * dictString = [self hexStringFromDictionary:playbackPositionDictionary];
ob[#"playbackPositionDictionaryString"] = dictString;
Retrieve From PFObject:
NSString * hexString = ob[#"playbackPositionDictionaryString"];
NSDictionary * playbackPositionDictionary = [self dictionaryFromHexString:hexString];
Related
I got a string with a particular format which have a Entity Name:#"Entry". I can't modify the string. How to access the string? I can access array objects but not inside. How to use initWithEntityName?
Here is the string
<__NSArrayI 0x7fe093f87160>(
<Entry: 0x600000498c90> (entity: Entry; id: 30506398-1852-433D-B536-DC57F484F754> ; data: {
cumulativeTime = 0000;
latitude = “12.972442”
longitude = "77.580643";
type = enrty;
entryName = Bangalore;
}),
<Entry: 0x600000498c90> (entity: Entry; id: 30506398-1852-433D-B536- DC57F484F754> ; data: {
cumulativeTime = 0000;
latitude = “13.067439”
longitude = "80.237617";
type = enrty;
entryName = Chennai;
})
This is how I got the array.
+(NSArray*) routePlan
{
NSString* jsonString = [NSString stringWithContentsOfURL:[[NSBundle mainBundle] URLForResource:#"Documents/DataJson" withExtension:nil]
encoding:NSUTF8StringEncoding error:nil];
NSArray* array = [jsonString componentsSeparatedByString:#","];
}
Do I need to use predicate?
I need the value of latitude and logtude. I can do "po array[0]", but can't go inside of array[0].
Get the below error if I try to access latitude.
error: Execution was interrupted, reason: Attempted to dereference an invalid ObjC Object or send it an unrecognized selector.
The process has been returned to the state before expression evaluation.
If I do po array[0], I got the below.
<__NSArrayI 0x7fe093f87160>(
<Entry: 0x600000498c90> (entity: Entry; id: 30506398-1852-433D-B536-DC57F484F754> ; data: {
cumulativeTime = 0000;
latitude = “12.972442”
longitude = "77.580643";
type = enrty;
entryName = Bangalore;
})
First of all, your file is not in json format.
Now, when you do this :
NSString* aircraftJSONString = [NSString stringWithContentsOfURL:[[NSBundle mainBundle] URLForResource:#"Documents/AircraftDataJson" withExtension:nil]
encoding:NSUTF8StringEncoding error:nil];
NSArray* aircraftJsonFplWaypoints = [aircraftJSONString componentsSeparatedByString:#","];
You are actually splitting your text at the comma, that's why your aircraftJsonFplWaypoints contains 2 object :
Fist a string with value :
<__NSArrayI 0x7fe093f87160>( (entity: Entry;
id: 30506398-1852-433D-B536-DC57F484F754> ; data: { cumulativeTime =
0000; latitude = “12.972442” longitude = "77.580643"; type = enrty;
entryName = Bangalore; })
then a string with value
(entity: Entry; id: 30506398-1852-433D-B536-
DC57F484F754> ; data: { cumulativeTime = 0000; latitude = “13.067439”
longitude = "80.237617"; type = enrty; entryName = Chennai; })
What you have in aircraftJsonFplWaypoints are strings, not dictionary nor array. This will lead you nowhere.
What you need to do is to use regular expression to get what's in the {} . This should work:
{[^}]*}
So I'll do something like :
NSError * error;
NSString * pattern = #"\\{[^\\}]*\\}";
NSRegularExpression * regex = [[NSRegularExpression alloc] initWithPattern:pattern
options:0
error:&error];
NSArray<NSTextCheckingResult *> * matches = [regex matchesInString:aircraftJSONString options:NSMatchingReportCompletion range:NSMakeRange(0, aircraftJSONString.length)];
for(NSTextCheckingResult * match in matches)
{
NSString * substring = [aircraftJSONString substringWithRange:match.range];
// Remove the bracket
substring = [substring substringWithRange:NSMakeRange(1, substring.length - 2)];
// split around the ";" => get the llat/long
NSArray<NSString *>* parts = [substring componentsSeparatedByString:#";"];
NSString * latLong = parts[1];
/* continue to get the longitude and latitude */
}
}
but I would recommend to use a standard for input, for example instead of copy/paste the po output, you can serialize your objects to json with the NSJSONSerialisation API with would make storing/retrieving much easier.
It seems to be the data you are fetching from bundle file is not a valid JSON, it is something else. If it is the JSON data then the below will be the approach to get that.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"DataJson" ofType:#"json"];
NSLog(#"%#",filePath);
NSURL *url = [NSURL fileURLWithPath:filePath];
NSData *jsonData = [NSData dataWithContentsOfURL:url];
NSError *error = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:&error];
if (error == nil){
NSLog(#"#### JSON object #### %#",jsonObject);
}else{
NSLog(#"#### JSON parsing error #### %#",error);
}
But as you mentioned you have an Entry as ManagedObject, which means you are trying to fetch the data from core data. So that please confirm me how you are saving and fetching data from coredata. (provide me sample code).
If you feel that you are correct with your approach, then please try to print the Entry object properties.
+(NSArray*) routePlan
{
NSString* jsonString = [NSString stringWithContentsOfURL:[[NSBundle mainBundle] URLForResource:#"Documents/DataJson" withExtension:nil]
encoding:NSUTF8StringEncoding error:nil];
NSArray* array = [jsonString componentsSeparatedByString:#","];
[array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger index, BOOL * _Nonnull stop)
{
Entry* entry = (Entry*)obj;
NSLog(#"id is :: %#",entry.id);
NSLog(#"id is :: %#",entry.data);
}];
return nil;
}
Below is my code to access the JSON API from Edmunds.com, this works perfectly to access the information I am just having trouble with accessing the key, value pairs.
NSURL *equipmentURL = [NSURL URLWithString: [NSString stringWithFormat:#"https://api.edmunds.com/api/vehicle/v2/styles/%#/equipment?fmt=json&api_key=%#", self.carID, apiKey]];
NSData *jsonData = [NSData dataWithContentsOfURL:equipmentURL];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
self.engineArray = [NSMutableArray array];
NSArray *equipmentArray = [dataDictionary objectForKey:#"equipment"];
for (NSDictionary *carInfoDictionary in equipmentArray) {
NSArray *attributes = [carInfoDictionary objectForKey:#"attributes"];
NSLog(#"%#", attributes);
}
In the NSLog from the above code shows this:
2016-11-03 10:21:26.029 CarWise[25766:1896339] (
{
name = "Engine Immobilizer";
value = "engine immobilizer";
},
{
name = "Power Door Locks";
value = "hands-free entry";
},
{
name = "Anti Theft Alarm System";
value = "remote anti-theft alarm system";
}
)
My main question is how can I access the name and value for each array? Let's say I want to create a UILabel that will have the string of one of the values?
Probably this will help
// Array as per the post
NSArray *attributes = (NSArray *)[carInfoDictionary objectForKey:#"attributes"];
// Loop to iterate over the array of objects(Dictionary)
for (int i = 0; i < attributes.count; i++) {
NSDictionary * dataObject = [NSDictionary dictionaryWithDictionary:(NSDictionary *)attributes[i]];
// This is the value for key "Name"
NSString *nameData = [NSString stringWithString:[dataObject valueForKey:#"name"]];
NSLog(#"Value of key : (name) : %#", nameData);
}
I get data from my Background
NSString * jsonStr = data[#"result"];
NSData * jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
This is the JsonStr:
{"id":2,"name":"轮胎式起重机","brand":"中联","type":"QY130","weight":130.0,"isValid":"1","ext1":65.9,"ext2":34.6,"ext3":100.6,"ext4":75.0,"ext5":65805.0,"createTime":"2016-07-20 10:58:09"}
In JsonStr the value for #"ext1" is 65.9, but after jsonobject the value become '65.90000000000001'
This is the dic:
{
brand = "\U4e2d\U8054";
createTime = "2016-07-20 10:58:09";
ext1 = "65.90000000000001";
ext2 = "34.6";
ext3 = "100.6";
ext4 = 75;
ext5 = 65805;
id = 2;
isValid = 1;
name = "\U8f6e\U80ce\U5f0f\U8d77\U91cd\U673a";
type = QY130;
weight = 130;
}
What's wrong with this data?
When you use ext1 as NSNumber:
NSNumber *ext1 = #([dic[#"ext1"] floatValue]);
NSLog(#"%#", ext1);
It will be 65.9.
NSString:
NSString *ext1Str = [NSString stringWithFormat:#"%#",ext1];
NSLog(#"%#", ext1Str);
2016-08-01 13:19:46.969 OCDemo[2200:78063] 65.9
2016-08-01 13:19:46.970 OCDemo[2200:78063] 65.9
Database (
{
to = (NSString *)
from = (NSString *)
subject = (NSString *)
uid = int
body = (NSString *)
}, { ...
)
Downloaded (
{
to = (NSString *)
from = (NSString *)
subject = (NSString *)
uid = int
body = (null)
}, { ...
)
I immediately pull and load an NSArray of about 200 NSDictionay objects from my Database into my UITableView, then I download an NSArray of the same structured NSDictionary but without a body.
Q: How do I go through all 200 Downloaded NSDictionary to see if it isn't already in my Database NSArray by matching the key: "uid"?
This should do the trick:
NSArray *arrayOfNew = [arrayDownload filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"NOT (uid IN %#)", [arrayDataBase valueForKey:#"uid"]];
Tested with this sample data, if someone want to test it:
NSDictionary *dictionary0 = #{#"to":#"0",#"from":#"0",#"uid":#(0), #"body":#"0"};
NSDictionary *dictionary1 = #{#"to":#"1",#"from":#"1",#"uid":#(1), #"body":#"0"};
NSDictionary *dictionary2 = #{#"to":#"2",#"from":#"2",#"uid":#(2), #"body":#"0"};
NSDictionary *dictionary3 = #{#"to":#"3",#"from":#"3",#"uid":#(3), #"body":#"0"};
NSDictionary *dictionary4 = #{#"to":#"4",#"from":#"4",#"uid":#(2)};
NSDictionary *dictionary5 = #{#"to":#"5",#"from":#"5",#"uid":#(5)};
NSArray *arrayDataBase = #[dictionary0, dictionary1, dictionary2, dictionary3];
NSArray *arrayDownload = #[dictionary4, dictionary5];
//So the dictionary4 shouldn't be kept, and dictionary5 should be kept.
NSArray *arrayNew = [arrayDownload filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"NOT (uid IN %#)", [arrayDataBase valueForKey:#"uid"]]];
NSLog(#"arrayNew: %#", arrayNew);
Output:
arrayNew: (
{
from = 5;
to = 5;
uid = 5;
}
With this code you can iterate in two arrays called "Downloaded" and "Database" and check if their uid match. I'm not sure if you're looking for a more elegant solution.
for (NSDictionary *dictDownloaded in Downloaded) {
for (NSDictionary *dictDatabase in Database) {
if ([dictDownloaded objectForKey:#"uid"] == [dictDatabase objectForKey:#"uid"]) {
NSLog(#"Object with uid: %d is in database", [[dictDownloaded objectForKey:#"uid"] intValue]);
}
}
}
Beware of nested loops :)
If you use Arturo's example (which works!) and download 1000 messages, you will have a potential of O(n*m) = 1000*200 = 200.000 "calculation steps"
Larme's attempt is pretty elegant (I like predicates!) but it's hard to predict the time it will use for execution, because it's all encapsulated within NSPredicate.
So another attempt, based on Larme's example data, would be to use a dictionary with the uid as the key for fast lookup.
NSMutableDictionary *databaseLookupDictionary = [[NSMutableDictionary alloc]init];
databaseLookupDictionary[#(0)] = #{#"to":#"0",#"from":#"0",#"uid":#(0), #"body":#"0"};
databaseLookupDictionary[#(1)] = #{#"to":#"1",#"from":#"1",#"uid":#(1), #"body":#"0"};
databaseLookupDictionary[#(2)] = #{#"to":#"2",#"from":#"2",#"uid":#(2), #"body":#"0"};
databaseLookupDictionary[#(3)] = #{#"to":#"3",#"from":#"3",#"uid":#(3), #"body":#"0"};
/* your download code */
// example data
NSMutableArray *downloadedData = [[NSMutableArray alloc]init];
[downloadedData addObject: #{#"to":#"0",#"from":#"0",#"uid":#(3)}];
[downloadedData addObject: #{#"to":#"0",#"from":#"0",#"uid":#(4)}];
for(NSDictionary *downloadDataDict in downloadedData)
{
// will be executed for message #4
if(![databaseLookupDictionary.allKeys containsObject:downloadDataDict[#"uid"]])
{
NSLog(#"Unknown message data found: %#", downloadDataDict);
}
}
This runs in linear time (O(n)*O(1)) so you should be fine with the performance. But keep in mind: if your message database count grows, you should think about searching directly in CoreData.
I'm able to retrieve data from the weather map api, however I can't figure out how to exactly parse the data. I'm able to do it only for a certain part of it.
This is the JSON data:
{
base = "cmc stations";
clouds = {
all = 56;
};
cod = 200;
coord = {
lat = "29.66";
lon = "-82.3";
};
dt = 1403641995;
id = 4156404;
main = {
humidity = 74;
pressure = 1018;
temp = "304.08";
"temp_max" = "306.48";
"temp_min" = "302.15";
};
name = Gainesville;
rain = {
3h = 0;
};
sys = {
country = US;
message = "0.2087";
sunrise = 1403605821;
sunset = 1403656392;
};
weather = (
{
description = "broken clouds";
icon = 04d;
id = 803;
main = Clouds;
}
);
wind = {
deg = 153;
gust = "1.54";
speed = "0.51";
};
}
Now I am able to get only one part of it :
base = "cmc stations"
like this:
- (void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
NSLog(#"values %#",json);
NSLog(#"Checking values ------------ %#",[json objectForKey:#"cloud"]);
}
But when I try to do the same for other fields like
clouds
coord
main
I can't. I get a null value.
I'm guessing I need an additional NSDictionary or NSArray but just not sure how to go about it. Can someone please tell how can I do this? I'm mainly looking to get data from the main block :
humidity
temp
temp_max
temp_min
rain
sunrise
sunset
I think I have found a solution:
Here's how I'm getting the data:
NSString* base = [json objectForKey:#"base"];
NSLog(#"Value of first base variable: %#",base);
// NSArray* base = [json objectAtIndex:0];
NSArray *clouds = [json objectForKey:#"clouds"];
NSLog(#"Value of first clouds‹ variable: %#",clouds);
NSArray *coord = [json objectForKey:#"coord"];
NSLog(#"Value of first coord variable: %#",coord);
NSDictionary *main = [json objectForKey:#"main"];
NSLog(#"Value of first coord variable: %#",main);
NSArray* humidity = [main objectForKey:#"humidity"];
NSLog(#"humidity levels found manually : %#",humidity);
NSArray* temp_max = [main objectForKey:#"temp_max"];
NSLog(#"max temp levels found manually : %#",temp_max);
The problem is that most of those values are dictionaries, not arrays. When you see { } and colons (:) that will generally indicate the presence of a dictionary of key-value pairs, even though some of them may only have one such pair which might make it appear like an array or a stand-alone object.
To get clouds for instance:
NSDictionary *clouds = [json objectForKey:#"clouds"];
NSNumber *allClouds = [clouds objectForKey:#"all"];
NSLog(#"Value of first clouds‹ variable: %#",allClouds);
To get coord:
NSDictionary *coords = [json objectForKey:#"coord"];
NSNumber *lon = [coords objectForKey:#"lon"];
NSNumber *lat = [coords objectForKey:#"lat"];
NSLog(#"Value of lon is: %#",lon);