I have been working on a SOAP Web Service that uses a Caché to avoid HTTP requests when they have been done before.
When I try to save my NSDictionary to a file I get a error (I guess it is because it doesn't follow the Properties List structure) and I know how to fix it.
This is my code:
[self loadCache];
NSData *responseData;
NSMutableDictionary* dict = [_cache objectForKey:delegate.type];
if (dict != nil && [dict objectForKey:request.HTTPBody] != nil ) {
responseData = [dict objectForKey:request.HTTPBody];
} else {
NSHTTPURLResponse* urlResponse = nil;
NSError *error = [[NSError alloc] init];
responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];
if (dict == nil) {
dict = [[NSMutableDictionary alloc] init];
[_cache setObject:dict forKey:delegate.type];
[dict setObject:[NSNumber numberWithDouble:NSTimeIntervalSince1970] forKey:#"FECHA"];
}
if (responseData == nil) {
responseData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"test" ofType:#"xml"]];
}
NSLog(#"%#", [[request.HTTPBody copy] class]);
[dict setObject:responseData forKey:request.HTTPBody];
[self saveCache];
}
loadCache Function:
- (void)loadCache {
if (_loadedCache) return;
NSString* docsurl = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
docsurl = [docsurl stringByAppendingPathComponent:#"cache.txt"];
_cache = [[NSMutableDictionary alloc] initWithContentsOfFile:docsurl];
if (_cache == nil) _cache = [[NSMutableDictionary alloc] init];
}
saveCache Function:
- (void)saveCache {
NSString* docsurl = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
docsurl = [docsurl stringByAppendingPathComponent:#"cache.txt"];
if ([_cache writeToFile:docsurl atomically:YES]) {
NSLog(#"SAVED");
} else {
NSLog(#"ERROR");
}
}
NSData cannot be the "key" it is only able to be the "value"
As commented: Solved! I was trying to use NSData as KEY, and it can only be used as VALUE.
Related
Im loading a database from a website through JSON. When I download the database I use UTF8 to make all characters appear correctly and when I NSLOG them it all appears as it should. But when I analyze the data using JSON and afterwards try to filter out just a few of the words, the words with special characters become like this: "H\U00f6ghastighetst\U00e5g" where it should say: "Höghastighetståg".
I have tried to find a way to make the code convert the text back to UTF8 after filtering but somehow I can't make it happen. Would be really helpful for some answers.
NSError *error;
NSString *url1 = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://www.pumba.se/example.json"] encoding:NSUTF8StringEncoding error:&error];
NSLog(#"Before converting to NSData: %#", url1);
NSData *allCoursesData = [url1 dataUsingEncoding:NSUTF8StringEncoding];
NSMutableDictionary *JSONdictionary = [NSJSONSerialization
JSONObjectWithData:allCoursesData
options:kNilOptions
error:&error];
if( error )
{
NSLog(#"%#", [error localizedDescription]);
}
else {
NSMutableArray *allNames = [NSMutableArray array];
NSArray* entries = [JSONdictionary valueForKeyPath:#"hits.hits"];
for (NSDictionary *hit in entries) {
NSArray *versions = hit[#"versions"];
for (NSDictionary *version in versions) {
NSDictionary *properties = version[#"properties"];
NSString *status = [properties[#"Status"] firstObject];
NSString *name = [properties[#"Name"] firstObject];
if ([status isEqualToString:#"usable"]) {
[allNames addObject:name];
}
}
}
NSLog(#"All names: %#", allNames);
}}
try with
+ (NSString *)utf8StringEncoding:(NSString *)message
{
NSString *uniText = [NSString stringWithUTF8String:[message UTF8String]];
NSData *msgData = [uniText dataUsingEncoding:NSNonLossyASCIIStringEncoding];
message = [[NSString alloc] initWithData:msgData encoding:NSUTF8StringEncoding];
return message;
}
or
+ (NSString *)asciiStringEncoding:(NSString *)message
{
const char *jsonString = [message UTF8String];
NSData *jsonData = [NSData dataWithBytes:jsonString length:strlen(jsonString)];
message = [[NSString alloc] initWithData:jsonData encoding:NSNonLossyASCIIStringEncoding];
return message;
}
and this code can help you
+ (NSDictionary *)jsonStringToObject:(NSString *)jsonString
{
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *jsonResponse;
if (data)
jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
return jsonResponse;
}
+ (NSString *)objectToJsonString:(NSDictionary *)dict
{
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error];
if (jsonData.length > 0 && !error)
{
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
return jsonString;
}
return nil;
}
Cannot encode the data in ios which fetch from webservice.
- (NSData*)encodeDictionary:(NSDictionary*)dictionary {
NSMutableArray *parts = [[NSMutableArray alloc] init];
for (NSString *key in dictionary) {
NSString *encodedValue = [[NSString stringWithFormat:#"%#",[dictionary objectForKey:key]] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *encodedKey = [[NSString stringWithFormat:#"%#",key] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *part = [NSString stringWithFormat: #"%#=%#", encodedKey, encodedValue];
[parts addObject:part];
}
NSString *encodedDictionary = [parts componentsJoinedByString:#"&"];
return [encodedDictionary dataUsingEncoding:NSUTF8StringEncoding];
}
It seems you are encoding NSDictionary and generate a NSString. And again Encoding that NSString and returns it.
You may do it in easy way as below.
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionaryOrArrayToOutput
options:NSJSONWritingPrettyPrinted
error:&error];
if (! jsonData) {
NSLog(#"Got an error: %#", error);
} else {
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
You may return above jsonData in your function to achieve your requirement as below.
- (NSData*)encodeDictionary:(NSDictionary*)dictionary {
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary
options:NSJSONWritingPrettyPrinted
error:&error];
if (! jsonData) {
NSLog(#"Got an error: %#", error);
} else {
return jsonData;
}
}
In this method:
- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError *error = nil;
NSURL *videoURL = [self videoURLWithData:self.connectionData error:&error];
if (videoURL)
self.moviePlayer.contentURL = videoURL;
else if (self.elFields.count > 0)
[self startVideoInfoRequest];
else
[self finishWithError:error];
}
videoURL is returned as nil and hence, it is going to the error block. Youtube video id that I am using is "5Uls9v1nnss". What seems to be the issue?
the videoURLWithData method which is used to retrieve the videoURL is this :
- (NSURL *) videoURLWithData:(NSData *)data error:(NSError * __autoreleasing *)error
{
NSString *videoQuery = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSStringEncoding queryEncoding = NSUTF8StringEncoding;
NSDictionary *video = DictionaryWithQueryString(videoQuery, queryEncoding);
NSMutableArray *streamQueries = [[video[#"url_encoded_fmt_stream_map"] componentsSeparatedByString:#","] mutableCopy];
[streamQueries addObjectsFromArray:[video[#"adaptive_fmts"] componentsSeparatedByString:#","]];
NSMutableDictionary *streamURLs = [NSMutableDictionary new];
for (NSString *streamQuery in streamQueries)
{
NSDictionary *stream = DictionaryWithQueryString(streamQuery, queryEncoding);
NSString *type = stream[#"type"];
NSString *urlString = stream[#"url"];
if (urlString && [AVURLAsset isPlayableExtendedMIMEType:type])
{
NSURL *streamURL = [NSURL URLWithString:urlString];
NSString *signature = stream[#"sig"];
if (signature)
streamURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#&signature=%#", urlString, signature]];
if ([[DictionaryWithQueryString(streamURL.query, queryEncoding) allKeys] containsObject:#"signature"])
streamURLs[#([stream[#"itag"] integerValue])] = streamURL;
}
}
for (NSNumber *videoQuality in self.preferredVideoQualities)
{
NSURL *streamURL = streamURLs[videoQuality];
if (streamURL)
{
NSString *title = video[#"title"];
NSString *thumbnailSmall = video[#"thumbnail_url"];
NSString *thumbnailMedium = video[#"iurlsd"];
NSString *thumbnailLarge = video[#"iurlmaxres"];
NSMutableDictionary *userInfo = [NSMutableDictionary new];
if (title)
userInfo[XCDMetadataKeyTitle] = title;
if (thumbnailSmall)
userInfo[XCDMetadataKeySmallThumbnailURL] = [NSURL URLWithString:thumbnailSmall];
if (thumbnailMedium)
userInfo[XCDMetadataKeyMediumThumbnailURL] = [NSURL URLWithString:thumbnailMedium];
if (thumbnailLarge)
userInfo[XCDMetadataKeyLargeThumbnailURL] = [NSURL URLWithString:thumbnailLarge];
[[NSNotificationCenter defaultCenter] postNotificationName:XCDYouTubeVideoPlayerViewControllerDidReceiveMetadataNotification object:self userInfo:userInfo];
return streamURL;
}
}
if (error)
{
NSMutableDictionary *userInfo = [#{ NSURLErrorKey: self.connection.originalRequest.URL } mutableCopy];
NSString *reason = video[#"reason"];
if (reason)
{
reason = [reason stringByReplacingOccurrencesOfString:#"<br\\s*/?>" withString:#" " options:NSRegularExpressionSearch range:NSMakeRange(0, reason.length)];
NSRange range;
while ((range = [reason rangeOfString:#"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
reason = [reason stringByReplacingCharactersInRange:range withString:#""];
userInfo[NSLocalizedDescriptionKey] = reason;
}
NSInteger code = [video[#"errorcode"] integerValue];
*error = [NSError errorWithDomain:XCDYouTubeVideoErrorDomain code:code userInfo:userInfo];
}
return nil;
}
You should use the latest version (2.0.2 as of writing) of XCDYouTubeKit, the successor of XCDYouTubeVideoPlayerViewController. The video 5Uls9v1nnss should play fine.
I'm trying to follow this tutorial:
http://www.raywenderlich.com/12170/core-data-tutorial-how-to-preloadimport-existing-data-updated
In this tutorial show how build a script for create a sqlite and import data from json.
I have write this:
static NSManagedObjectModel *managedObjectModel()
{
static NSManagedObjectModel *model = nil;
if (model != nil) {
return model;
}
NSString *path = #"AppChecker";
path = [path stringByDeletingPathExtension];
NSURL *modelURL = [NSURL fileURLWithPath:[path stringByAppendingPathExtension:#"mom"]];
model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return model;
}
static NSManagedObjectContext *managedObjectContext()
{
static NSManagedObjectContext *context = nil;
if (context != nil) {
return context;
}
#autoreleasepool {
context = [[NSManagedObjectContext alloc] init];
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel()];
[context setPersistentStoreCoordinator:coordinator];
NSString *STORE_TYPE = NSSQLiteStoreType;
NSString *path = [[NSProcessInfo processInfo] arguments][0];
path = [path stringByDeletingPathExtension];
NSURL *url = [NSURL fileURLWithPath:[path stringByAppendingPathExtension:#"sqlite"]];
NSError *error;
NSPersistentStore *newStore = [coordinator addPersistentStoreWithType:STORE_TYPE configuration:nil URL:url options:nil error:&error];
if (newStore == nil) {
NSLog(#"Store Configuration Failure %#", ([error localizedDescription] != nil) ? [error localizedDescription] : #"Unknown Error");
}
}
return context;
}
int main(int argc, const char * argv[])
{
#autoreleasepool {
// Create the managed object context
NSManagedObjectContext *context = managedObjectContext();
// Custom code here...
// Save the managed object context
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Error while saving %#", ([error localizedDescription] != nil) ? [error localizedDescription] : #"Unknown Error");
exit(1);
}
NSError* err = nil;
NSString* dataPath = [[NSBundle mainBundle] pathForResource:#"brands" ofType:#"json"];
NSArray* Brands = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath]
options:kNilOptions
error:&err];
NSLog(#"Imported Brands: %#", Brands);
NSString* dataPath2 = [[NSBundle mainBundle] pathForResource:#"products" ofType:#"json"];
NSArray* Products = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath2]
options:kNilOptions
error:&err];
NSLog(#"Imported Products: %#", Products);
}
return 0;
}
The problem is that, it create the .sqlite database(and structure is ok), but there isn't data!!!
My db is so:
And this is my json of brands for example:
[{
"id":"1",
"name":"TestBrand",
"description":"",
"website":"",
"email":"",
"address":"",
"phone":"",
"from_country_list":"CZ",
"created_at":"2013-11-24 11:51:17.363473",
"updated_at":"2013-11-24 11:51:17.363473"
}]
Any help/tips on why the data isn't imported in .sqlite db ?
Thanks a lot.
Continue with the tutorial. You will have to iterate through your objects created from the JSON files and add each instance to the Core Data object graph, populate it with the available attributes and finally save the context.
Only after this last step will the data be stored in the sqlite database.
In my iOS app I'm using the weather APIs of worldweatheronline.com but I get a random "EXC_BAD_ACCESS" error oh this row (not always but sometimes) :
temperature.text = [NSString stringWithFormat:#"%# °C", tempC];
Here is my code:
- (void)showWeatherFor:(CLLocation *)newLocation
{
NSString *myRequestString = [[NSString alloc] initWithFormat:#"http://api.worldweatheronline.com/free/v1/weather.ashx?q=%f,%f&format=json&num_of_days=5&key=ydvgep8jn5m846upd8kb2qp6", newLocation.coordinate.latitude, newLocation.coordinate.longitude];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:myRequestString]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *JsonString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSError *error = nil;
NSDictionary *theDictionary = [NSDictionary dictionaryWithJSONString:JsonString error:&error];
NSDictionary *data = [theDictionary objectForKey:#"data"];
NSArray *currentDictionary = [data objectForKey:#"current_condition"];
NSDictionary *temp = [currentDictionary objectAtIndex:0];
if ([temp objectForKey:#"temp_C"] == nil || [temp objectForKey:#"temp_F"] == nil)
{
return;
termometro.alpha = 0;
}
else
{
if (temp != nil)
{
if ([mainDelegate.gradi isEqualToString: #"°C"])
{
NSNumber *tempC = [temp objectForKey:#"temp_C"];
temperature.text = [NSString stringWithFormat:#"%# °C", tempC];
mainDelegate.temperature = [[temp objectForKey:#"temp_C"]intValue];
}
else
{
NSNumber *tempF = [temp objectForKey:#"temp_F"];
temperature.text = [NSString stringWithFormat:#"%# °F", tempF];
mainDelegate.temperature = [[temp objectForKey:#"temp_F"]intValue];
}
termometro.alpha = 1;
}
}
}