I am making a async request and I'm getting a EXC_BAD_ACCESS on [responseData setLength:0];
The Code is:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Connection failed: %#", [error description]);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
luckyNumbers1 = [responseString JSONValue];
NSUserDefaults *information = [NSUserDefaults standardUserDefaults];
/*NSArray *luckyNumbers = [json objectWithString:responseString error:&error];*/
NSLog(#"luckyNumbers1: %#", luckyNumbers1);
NSLog(#"user Info array is: %#", luckyNumbers1);
// [information setObject:[NSString stringWithFormat:#"%#", (NSString *)[luckyNumbers1 objectForKey:#"session"]] forKey:#"sessionID"];
NSDictionary *array = (NSDictionary *)[luckyNumbers1 objectForKey:#"data"];
NSEnumerator *inner = [luckyNumbers1 objectEnumerator];
id value;
while((value = [inner nextObject])) {
NSLog(#"user Info array is: %#", value);
if ( [value isKindOfClass:[NSDictionary class]] ) {
[information setObject:[value objectForKey:#"id"] forKey:#"userID"];
NSLog(#"uid is: %#", [value objectForKey:#"id"]);
[information setObject:[NSString stringWithFormat:#"%#", (NSString *)[value objectForKey:#"points_all"]] forKey:#"pointString"];
[information setObject:[NSString stringWithFormat:#"%#", (NSString *)[[[value objectForKey:#"leaderboards"] objectForKey:#"all"] objectForKey:#"position"]] forKey:#"rankString"];
if ((NSNull *)[value objectForKey:#"display_name"] == [NSNull null]) {
[information setObject:#"No Display Name" forKey:#"displayNameString"];
} else {
[information setObject:[NSString stringWithFormat:#"%#", (NSString *)[value objectForKey:#"display_name"]] forKey:#"displayNameString"];
}
if ((NSNull *)[value objectForKey:#"level"] == [NSNull null]) {} else {
[information setObject:[NSString stringWithFormat:#"%#", (NSString *)[[[value objectForKey:#"level"] objectForKey:#"definition"] objectForKey:#"name"]] forKey:#"levelString"];
}
pointsTV = [[UILabel alloc] initWithFrame:CGRectMake(222, 294, 441, 22)];
pointsTV.text = [NSString stringWithFormat:#"Points: %#", [information stringForKey:#"pointString"]];
pointsTV.backgroundColor = [UIColor clearColor];
pointsTV.textColor = [UIColor whiteColor];
[TVWindow addSubview:pointsTV];
rankLabelTV = [[UILabel alloc] initWithFrame:CGRectMake(222, 269, 441, 22)];
rankLabelTV.backgroundColor = [UIColor clearColor];
rankLabelTV.textColor = [UIColor whiteColor];
rankLabelTV.text = [NSString stringWithFormat:#"Rank: %#", (NSString *)[[[array objectForKey:#"leaderboards"] objectForKey:#"all"] objectForKey:#"position"]];
[TVWindow addSubview:rankLabelTV];
levelNameLabelTV = [[UILabel alloc] initWithFrame:CGRectMake(222, 244, 441, 22)];
levelNameLabelTV.backgroundColor = [UIColor clearColor];
levelNameLabelTV.textColor = [UIColor whiteColor];
if ((NSNull *)[value objectForKey:#"level"] == [NSNull null]) {
levelNameLabelTV.text = #"No Level";
} else {
levelNameLabelTV.text = [NSString stringWithFormat:#"Level: %#", (NSString *)[[[array objectForKey:#"level"] objectForKey:#"definition"] objectForKey:#"name"]];
}
[TVWindow addSubview:levelNameLabelTV];
pointLabel.text = [information stringForKey:#"pointString"];
pointLabel.textAlignment = UITextAlignmentLeft;
displayNameLabelTV.text = [information stringForKey:#"displayNameString"];
displayNameLabel. text = [information stringForKey:#"displayNameString"];
rankLabel.text = [information stringForKey:#"rankString"];
levelLabel.text = [information stringForKey:#"levelString"];
NSURL *url1 = [NSURL URLWithString: [NSString stringWithFormat:#"%#", (NSString *)[array objectForKey:#"picture_url"]]];
NSData *urlData1 = [NSData dataWithContentsOfURL:url1];
UIImage *image1 = [UIImage imageWithData:urlData1];
profilePicture.image = image1;
profilePictureTV.image = image1;
[information setObject:[NSString stringWithFormat:#"%#", (NSString *)[luckyNumbers1 objectForKey:#"session"]] forKey:#"sessionID"];
}}
NSURLRequest *request2;
request2 = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://%#/api/widgets/%#/%#/players/%#/rewards.json", [information stringForKey:#"host"], [information objectForKey:#"apiKey"], [information objectForKey:#"URL"], [information objectForKey:#"userID"]]]];
NSLog(#"Badges Request is: %#", request2);
NSURLConnection *connection2;
connection2 = [[NSURLConnection alloc] initWithRequest:request2 delegate:self startImmediately:YES];
NSURLResponse *resp3;
NSData *cData2 = [NSURLConnection sendSynchronousRequest:request2 returningResponse:&resp3 error:nil];
NSString *cDataString2 = [[NSString alloc] initWithData:cData2 encoding:NSUTF8StringEncoding];
[self getUsersBadges: cDataString2];
[[NSURLConnection alloc] initWithRequest:request2 delegate:self];
// pass cDataString into the JSON parser and update points
[connection release];
}
Without seeing your initialization of reponseData, it’s hard to be sure, but I would guess that you’re either declaring it as [NSMutableData data] (which will get autoreleased) or release/autoreleaseing it before you get to -connection:didReceiveResponse:. The solution is to make sure it doesn’t get released early, either by calling retain on it or by initializing it with [[NSMutableData alloc] init]. In either case, you’ll need to release it once you’re done, though it looks as if you’re doing that already in your -connectionDidFinishLoading:, so no change needed there.
Related
i added website field in core data after adding other attributes to xcdatamodel, and i am saving this attribute like this
- (void)fetchandSaveGWTGsSince:(NSString *)since
{
NSString *completeURL = [NSString stringWithFormat:#"%#api.php?action=get_all_gwtgs&sinceDate=%#", BASE_URL, since];
NSURL *url = [NSURL URLWithString:completeURL];
// self.loggingEnable = NO;
if (self.loggingEnable == YES)
{
NSLog(#"%#", [NSString stringWithFormat:#"%i", [since integerValue]-18000]);
NSLog(#"%#", since);
NSLog(#"%#", [[NSDate dateWithTimeIntervalSince1970:(NSTimeInterval)[since integerValue]] description]);
NSLog(#"%#", [[NSDate dateWithTimeIntervalSince1970:((NSTimeInterval)[since integerValue])-18000] description]);
NSLog(#"%#", completeURL);
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.timeoutInterval = REQUEST_TIMEOUT;
[AFJSONRequestOperation addAcceptableContentTypes:[NSSet setWithObject:#"text/html"]];
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON)
{
NSDictionary *resDict = (NSDictionary *)JSON;
if (self.loggingEnable == YES)
{
NSLog(#"Response GWTGs : %#", resDict);
}
if ([[resDict objectForKey:#"status"] isEqualToString:#"success"])
{
NSArray *data = [[resDict objectForKey:#"data"] objectAtIndex:0];
NSManagedObjectContext *context = [[Common apd] managedObjectContext];
if ([data count] > 0)
{
[data enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
NSDictionary *gwtgDict = (NSDictionary *)obj;
if ([gwtgDict objectForKey:#"gwtg_id"])
{
NSArray *locationInfos = [self getGWTGsWithGWTG_ID:[gwtgDict objectForKey:#"gwtg_id"]];
if ([locationInfos count] > 0)
{
for (Location *location in locationInfos)
{
[context deleteObject:location];
NSError *error = nil;
if (![context save:&error]) {
// Handle the error.
if (self.loggingEnable == YES)
{
NSLog(#"error deleting gwtg : %#", [location description]);
}
}
}
}
}
}];
}
[data enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
NSDictionary *gwtgInfo = (NSDictionary *)obj;
/*
gwtg_status = 0 => Inactive Record
gwtg_status = 1 => New Record/Active Record
gwtg_status = 2 => Updated Record
gwtg_status = 3 => Deleted Record
*/
if ([[gwtgInfo objectForKey:#"gwtg_status"] intValue] != 3)
{
GWTG *gwtg = [NSEntityDescription insertNewObjectForEntityForName:#"GWTG" inManagedObjectContext:context];
gwtg.gwtg_id = ([[gwtgInfo objectForKey:#"gwtg_id"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"gwtg_id"];
NSData *celData = [NSData dataWithBase64EncodedString:[gwtgInfo objectForKey:#"celebrity_name"]];
NSString *celName = [[NSString alloc] initWithData:celData encoding:NSStringEncodingConversionAllowLossy];
gwtg.celebrity_name = ([celName isKindOfClass:[NSNull class]]) ? #"" : celName;
gwtg.location_id = ([[gwtgInfo objectForKey:#"location_id"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"location_id"];
NSData *loc_cityData = [NSData dataWithBase64EncodedString:[gwtgInfo objectForKey:#"location_city"]];
NSString *loc_cityName = [[NSString alloc] initWithData:loc_cityData encoding:NSStringEncodingConversionAllowLossy];
gwtg.location_city = ([loc_cityName isKindOfClass:[NSNull class]]) ? #"" : loc_cityName;
NSData *cityData = [NSData dataWithBase64EncodedString:[gwtgInfo objectForKey:#"city"]];
NSString *cityName = [[NSString alloc] initWithData:cityData encoding:NSStringEncodingConversionAllowLossy];
gwtg.city = ([cityName isKindOfClass:[NSNull class]]) ? #"" : cityName;
NSData *stateData = [NSData dataWithBase64EncodedString:[gwtgInfo objectForKey:#"state"]];
NSString *stateName = [[NSString alloc] initWithData:stateData encoding:NSStringEncodingConversionAllowLossy];
gwtg.state = ([stateName isKindOfClass:[NSNull class]]) ? #"" : stateName;
NSData *countryData = [NSData dataWithBase64EncodedString:[gwtgInfo objectForKey:#"country"]];
NSString *countryName = [[NSString alloc] initWithData:countryData encoding:NSStringEncodingConversionAllowLossy];
gwtg.country = ([countryName isKindOfClass:[NSNull class]]) ? #"" : countryName;
gwtg.a_consuming = ([[gwtgInfo objectForKey:#"a_consuming"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"a_consuming"];
gwtg.a_playing = ([[gwtgInfo objectForKey:#"a_playing"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"a_playing"];
gwtg.a_lodging = ([[gwtgInfo objectForKey:#"a_lodging"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"a_lodging"];
gwtg.a_shopping = ([[gwtgInfo objectForKey:#"a_shopping"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"a_shopping"];
gwtg.a_recommending = ([[gwtgInfo objectForKey:#"a_recommending"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"a_recommending"];
gwtg.w_g_here = ([[gwtgInfo objectForKey:#"w_g_here"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"w_g_here"];
NSData *locData = [NSData dataWithBase64EncodedString:[gwtgInfo objectForKey:#"location_name"]];
NSString *locName = [[NSString alloc] initWithData:locData encoding:NSStringEncodingConversionAllowLossy];
gwtg.location_name = ([locName isKindOfClass:[NSNull class]]) ? #"" : locName;
//location_address, we_go_here, credit
NSData *locAdData = [NSData dataWithBase64EncodedString:[gwtgInfo objectForKey:#"location_address"]];
NSString *locAdName = [[NSString alloc] initWithData:locAdData encoding:NSStringEncodingConversionAllowLossy];
gwtg.location_address = ([locAdName isKindOfClass:[NSNull class]]) ? #"" : locAdName;
gwtg.location_phone = ([[gwtgInfo objectForKey:#"location_phone"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"location_phone"];
gwtg.location_zip_code = ([[gwtgInfo objectForKey:#"location_zip_code"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"location_zip_code"];
NSData *wghData = [NSData dataWithBase64EncodedString:[gwtgInfo objectForKey:#"we_go_here"]];
NSString *wghName = [[NSString alloc] initWithData:wghData encoding:NSStringEncodingConversionAllowLossy];
gwtg.we_go_here = ([wghName isKindOfClass:[NSNull class]]) ? #"" : wghName;
gwtg.wgh_date = ([[gwtgInfo objectForKey:#"wgh_date"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"wgh_date"];
NSData *creData = [NSData dataWithBase64EncodedString:[gwtgInfo objectForKey:#"credit"]];
NSString *creName = [[NSString alloc] initWithData:creData encoding:NSStringEncodingConversionAllowLossy];
gwtg.credit = ([creName isKindOfClass:[NSNull class]]) ? #"" : creName;
NSData *webSite_Data = [NSData dataWithBase64EncodedString:[gwtgInfo objectForKey:#"website"]];
NSString *add_website = [[NSString alloc] initWithData:webSite_Data encoding:NSStringEncodingConversionAllowLossy];
gwtg.website = ([add_website isKindOfClass:[NSNull class]]) ? #"" : add_website;
gwtg.gwtg_status = ([[gwtgInfo objectForKey:#"gwtg_status"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"gwtg_status"];
gwtg.gwtg_isactive = ([[gwtgInfo objectForKey:#"gwtg_isactive"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"gwtg_isactive"];
gwtg.addeddate = ([[gwtgInfo objectForKey:#"addeddate"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"addeddate"];
gwtg.modifieddate = ([[gwtgInfo objectForKey:#"modifieddate"] isKindOfClass:[NSNull class]]) ? #"" : [gwtgInfo objectForKey:#"modifieddate"];
if (self.loggingEnable == YES)
{
NSLog(#"----Location----");
NSLog(#"%#", gwtg.gwtg_id);
NSLog(#"%#", gwtg.celebrity_name);
NSLog(#"%#", gwtg.location_id);
NSLog(#"%#", gwtg.city);
NSLog(#"%#", gwtg.state);
NSLog(#"%#", gwtg.country);
NSLog(#"%#", gwtg.a_consuming);
NSLog(#"%#", gwtg.a_playing);
NSLog(#"%#", gwtg.a_lodging);
NSLog(#"%#", gwtg.a_shopping);
NSLog(#"%#", gwtg.a_recommending);
NSLog(#"%#", gwtg.w_g_here);
NSLog(#"%#", gwtg.location_name);
NSLog(#"%#", gwtg.location_address);
NSLog(#"%#", gwtg.location_phone);
NSLog(#"%#", gwtg.location_zip_code);
NSLog(#"%#", gwtg.we_go_here);
NSLog(#"%#", gwtg.wgh_date);
NSLog(#"%#", gwtg.credit);
NSLog(#"%#", gwtg.website);
NSLog(#"%#", gwtg.gwtg_status);
NSLog(#"%#", gwtg.addeddate);
NSLog(#"%#", gwtg.modifieddate);
NSLog(#"%#", gwtg.gwtg_isactive);
}
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}
}];
if ([[NSUserDefaults standardUserDefaults] objectForKey:LAST_TIME_GWTG_UPDATED])
{
[[NSUserDefaults standardUserDefaults] removeObjectForKey:LAST_TIME_GWTG_UPDATED];
}
NSDate *date = [NSDate date];
NSLog(#"date last time : %#", [data description]);
[[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithFormat:#"%.f", [date timeIntervalSince1970]] forKey:LAST_TIME_GWTG_UPDATED];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationRequestFinished object:nil userInfo:nil];
}
else
{
// [Common showAlertWithTitle:#"Warning" message:[resDict objectForKey:#"message"]];
if ([[NSUserDefaults standardUserDefaults] objectForKey:LAST_TIME_GWTG_UPDATED])
{
}
else
{
[[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithFormat:#"0"] forKey:LAST_TIME_GWTG_UPDATED];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON)
{
if (self.loggingEnable == YES)
{
NSLog(#"error %#", [error description]);
}
[Common showAlertWithTitle:#"Error Retrieving" message:[NSString stringWithFormat:#"%#",[error localizedDescription]]];
if ([[NSUserDefaults standardUserDefaults] objectForKey:LAST_TIME_GWTG_UPDATED])
{
}
else
{
[[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithFormat:#"0"] forKey:LAST_TIME_GWTG_UPDATED];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}];
[operation start];
}
and i am getting website url like this, but it always come empty,
NSString *urlString = [NSString stringWithFormat:#"%#", _gwtgDO.website];
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[[UIApplication sharedApplication] openURL:url];
why it is always empty although i am getting website link from server correctly? is this due to reason that i added attribute later? what should i do now?
You are passing NSStringEncodingConversionOptions instead of NSStringEncoding. I suppose you want NSString *add_website = [[NSString alloc] initWithData:webSite_Data encoding:NSUTF8StringEncoding]; for UTF-8 encoding, for example.
More about the encodings here: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html
I m doing the concept of autocomplete feature for a textField and in doing so I m getting the following error:
"cfstring length message sent to deallocated instance"
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if( textField == txtcity)
{
autocompleteTableView.hidden = NO;
NSString *substring = [NSString stringWithString:textField.text];
substring = [substring stringByReplacingCharactersInRange:range withString:string];
[self searchAutocompleteEntriesWithSubstring:substring];
return YES;
}
}
- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring {
subString2=[NSString stringWithFormat:#"%#",substring];
NSMutableData *data = [[NSMutableData alloc] init];
self.receivedData = data;
[data release];
NSURL *jsonUrl =[NSURL URLWithString:[NSString stringWithFormat:#"http://210.90.32.122/services/AutoService.svc/GetCities/?p=%#&k=%#",substring,txtId.text]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:jsonUrl];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
self.connection = connection;
[connection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
parser = [[NSXMLParser alloc] initWithData:receivedData];
[parser setDelegate:self];
[parser setShouldProcessNamespaces:NO];
[parser setShouldReportNamespacePrefixes:NO];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
[parser release];
NSLog(#"%#",arr2);
if([arr2 count]!=0)
{
self.autocompleteUrls = [[NSMutableArray alloc] init];
if(autocompleteTableView)
[autocompleteTableView removeFromSuperview];
autocompleteTableView = [[UITableView alloc] initWithFrame:CGRectMake(88, 428, 200,[arr2 count]*20) style:UITableViewStyleGrouped];
autocompleteTableView.delegate = self;
autocompleteTableView.dataSource = self;
autocompleteTableView.scrollEnabled = YES;
autocompleteTableView.rowHeight=20;
[self.view addSubview:autocompleteTableView];
for(int i=0;i<[arr2 count];i++)
{
NSString *curString = [[arr2 objectAtIndex:i] valueForKey:#"Name"];
NSRange substringRange = [curString rangeOfString:subString2]; //error at this line
if (substringRange.location == 0)
[autocompleteUrls addObject:curString];
}
}
[autocompleteTableView reloadData];
txtcity.text=subString2;
[txtcity resignFirstResponder];
}
my subString2 is becoming null.But I have retained it while decalring
#property(nonatomic,retain)NSString *subString2;
Where Im going wrong.Couldn't understand where it is being deallocated..
You're not actually retain it. You're setting the object variable subString2 not though the property, that is the reason. Try this:
self.subString2 = [NSString stringWithFormat:#"%#",substring];
But it is not very good practise to get to the object variables from the object through the properties. There is two options:
[subString2 release];
subString2 = [[NSString stringWithFormat:#"%#",substring] copy];
OR
[subString2 release];
subString2 = [[NSString stringWithFormat:#"%#",substring] retain];
This XML will be included in the app:
<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Directory</title>
<description>Directory of Members</description>
<language>en</language>
<item>
<LastName></LastName>
<FirstName></FirstName>
<Address></Address>
<Phone></Phone>
<Email></Email>
</item>
<item>
<LastName></LastName>
<FirstName></FirstName>
<Address></Address>
<Phone></Phone>
<Email></Email>
</item>
</channel>
</rss>
I would like to be able to parse the XML and store into an RSSEntry Class that I have done before with other XMLs. The issue is that the only other XMLs I have worked with have been located online, and I use ASIHttpRequest Classes as part of the method, and am unsure how to go about changing the code to make it fit. I currently use this code:
- (void)viewDidLoad {
[super viewDidLoad];
self.allEntries = [NSMutableArray array];
self.queue = [[[NSOperationQueue alloc] init] autorelease];
self.feeds = [NSArray arrayWithObjects:#"http://316apps.com/LakesideNews/feed/",
nil];
NSLog(#"%#", self.feeds);
[self refresh];
}
- (void)refresh {
for (NSString *feed in _feeds) {
NSURL *url = [NSURL URLWithString:feed];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[_queue addOperation:request];
}
}
- (void)parseRss:(GDataXMLElement *)rootElement entries:(NSMutableArray *)entries {
NSArray *channels = [rootElement elementsForName:#"channel"];
for (GDataXMLElement *channel in channels) {
NSString *blogTitle = [channel valueForChild:#"title"];
NSArray *items = [channel elementsForName:#"item"];
for (GDataXMLElement *item in items) {
NSString *articleTitle = [item valueForChild:#"title"];
NSString *articleUrl = [item valueForChild:#"guid"];
NSString *articleDateString = [item valueForChild:#"pubDate"];
NSDate *articleDate = [NSDate dateFromInternetDateTimeString:articleDateString formatHint:DateFormatHintRFC822];
NSString *articleImage = [item valueForChild:#"content:encoded"];
RSSEntry *entry = [[[RSSEntry alloc] initWithBlogTitle:blogTitle
articleTitle:articleTitle
articleUrl:articleUrl
articleDate:articleDate
articleImage:articleImage] autorelease];
[entries addObject:entry];
}
}
}
- (void)parseFeed:(GDataXMLElement *)rootElement entries:(NSMutableArray *)entries {
if ([rootElement.name compare:#"rss"] == NSOrderedSame) {
[self parseRss:rootElement entries:entries];
} else if ([rootElement.name compare:#"feed"] == NSOrderedSame) {
[self parseAtom:rootElement entries:entries];
} else {
NSLog(#"Unsupported root element: %#", rootElement.name);
}
}
- (void)requestFinished:(ASIHTTPRequest *)request {
[_queue addOperationWithBlock:^{
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:[request responseData]
options:0 error:&error];
if (doc == nil) {
NSLog(#"Failed to parse %#", request.url);
} else {
NSMutableArray *entries = [NSMutableArray array];
[self parseFeed:doc.rootElement entries:entries];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
for (RSSEntry *entry in entries) {
int insertIdx = [_allEntries indexForInsertingObject:entry sortedUsingBlock:^(id a, id b) {
RSSEntry *entry1 = (RSSEntry *) a;
RSSEntry *entry2 = (RSSEntry *) b;
return [entry1.articleDate compare:entry2.articleDate];
}];
[_allEntries insertObject:entry atIndex:insertIdx];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:insertIdx inSection:0]]
withRowAnimation:UITableViewRowAnimationRight];
}
}];
}
}];
}
- (void)requestFailed:(ASIHTTPRequest *)request {
NSError *error = [request error];
NSLog(#"Error: %#", error);
[self refresh];
}
I know to change all the areas for Title to things like Family name, etc., I just don't know how to go about getting the GDataXML to begin parsing the nested XML.
Ray Wenderlich has a fantastic tutorial covering exactly what you are doing. I would start there. Here's the link.
I try to load some image on my UITableView with ASIHTTP but I have some problems. First of all I read an xml file (with tbxml) and I save title, image path and description in a dictionary and then in an array, for parsing I use this code:
- (void)loadUnknownXML {
// Load and parse the books.xml file
tbxml = [TBXML tbxmlWithURL:[NSURL URLWithString:#"http://www.xxx.com"]];
// If TBXML found a root node, process element and iterate all children
if (tbxml.rootXMLElement){
[self traverseElement:tbxml.rootXMLElement];
}
}
- (void) traverseElement:(TBXMLElement *)element {
TBXMLElement *child = element->firstChild;
TBXMLElement *items = [TBXML childElementNamed:#"item" parentElement:child];
do{
if (items->firstChild) {
TBXMLElement *titolo = [TBXML childElementNamed:#"title" parentElement:items];
TBXMLElement *descrizione = [TBXML childElementNamed:#"description" parentElement:items];
//NSLog(#"Titolo: %# \n Descrizione: %#",[TBXML textForElement:titolo],[TBXML textForElement:descrizione]);
self.elemento = [[NSMutableDictionary alloc] init];
[self.elemento setObject:[TBXML textForElement:titolo] forKey:#"Titolo"];
NSString *indirizzoImmagine = [TBXML textForElement:descrizione];
NSRange rangeSRC = [indirizzoImmagine rangeOfString:#"src=\""];
indirizzoImmagine = [indirizzoImmagine substringFromIndex:NSMaxRange(rangeSRC)];
NSRange rangeAMP = [indirizzoImmagine rangeOfString:#"&"];
NSRange rangeWidth = [indirizzoImmagine rangeOfString:#"&width"];
if (rangeAMP.location != NSNotFound) {
indirizzoImmagine = [indirizzoImmagine substringToIndex:NSMaxRange(rangeAMP)];
}
else if (rangeWidth.location != NSNotFound){
indirizzoImmagine = [indirizzoImmagine substringToIndex:NSMaxRange(rangeWidth)];
}
indirizzoImmagine = [indirizzoImmagine stringByReplacingOccurrencesOfString:#"&" withString:#""];
indirizzoImmagine = [indirizzoImmagine stringByReplacingOccurrencesOfString:#"&width" withString:#""];
[self.elemento setObject:indirizzoImmagine forKey:#"IndirizzoImmagine"];
[self.elemento setObject:[TBXML textForElement:descrizione] forKey:#"Descrizione"];
[self.array addObject:self.elemento];
}
}
while ((items=items->nextSibling));
}
then I start with download
- (void) loadURL:(NSURL *)url index:(int)index
{
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
ASIDownloadCache *cache = [[ASIDownloadCache alloc] init];
[request setDownloadCache:cache];
[request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
[request setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
[cache setStoragePath:#"/Users/kikko/kikko/xxx"];
request.userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:index], #"index",
url, #"url", nil];
[request setDelegate:self];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
int index = [[request.userInfo valueForKey:#"index"] intValue];
ASIDownloadCache *cache = [[ASIDownloadCache alloc] init];
[cache setStoragePath:#"/Users/kikko/kikko/xxx"];
[request.userInfo valueForKey:#"url"];
if ([cache cachedResponseDataForURL:[request.userInfo valueForKey:#"url"]]==nil) {
NSLog(#"%#",[request.userInfo valueForKey:#"url"]);
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:index inSection:0];
NSArray* rows = [NSArray arrayWithObjects:indexPath, nil];
[table reloadRowsAtIndexPaths:rows withRowAnimation:UITableViewRowAnimationNone];
}
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"Error: %#",error);
}
at the end I put the image inside cell.imageview
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.array.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 50;
}
-(NSString *) stringByStrippingHTML:(NSString *)stringa {
NSRange r;
NSString *str = stringa;
while ((r = [str rangeOfString:#"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
str = [str stringByReplacingCharactersInRange:r withString:#""];
return str;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"ItemCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
elemento = [array objectAtIndex:indexPath.row];
NSURL *indirizzoImmagine = [NSURL URLWithString:[elemento objectForKey:#"IndirizzoImmagine"]];
[self loadURL:indirizzoImmagine index:indexPath.row];
ASIDownloadCache *cache = [[ASIDownloadCache alloc] init];
[cache setStoragePath:#"/Users/kikko/kikko/xxx"];
dataImmagine = [cache cachedResponseDataForURL:indirizzoImmagine];
[cell.imageView setImage:[UIImage imageWithData:dataImmagine]];
cell.textLabel.text = [elemento objectForKey:#"Titolo"];
return cell;
}
There are a lot of ways to go about this, but the most minimally invasive way to your existing code is to attach a userinfo dictionary to your request object.
In your traverse method do this:
//...
while ((items=items->nextSibling));
for (int i = 0; i < [self.array count]; i++)
{
[arrayData addObject:[NSNull null]];
}
Then do this in your request methods
- (void) loadURL:(NSURL *)url index:(int)index
{
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadCache:[ASIDownloadCache sharedCache]];
[request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
[request setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
request.userInfo = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:index], #"index", nil];
[request setDelegate:self];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSData *responseData = [request responseData];
int index = [[request.userInfo valueForKey:#"index"] intValue];
[arrayData replaceObjectAtIndex:index withObject:responseData];
//EDIT below:
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:index inSection:0];
NSArray* rows = [NSArray arrayWithObjects:indexPath, nil];
[self.tableView reloadRowsAtIndexPaths:rows withRowAnimation:UITableViewRowAnimationNone];
}
In your cell code, do this:
if ([arrayData objecAtIndex:indexPath.row] != [NSNull null]) {
UIImage *img = [UIImage imageWithData:[self.arrayData objectAtIndex:indexPath.row]];
imageView.image = img;
[cell.imageView setImage:img];
} else {
imageView.image = nil;
}
There is best example given by Apple to download and show images Asyn
https://developer.apple.com/library/ios/#samplecode/LazyTableImages/Introduction/Intro.html
Meanwhile i will check your code as well
I'm building my custom cell for a table view. I'm trying to load an image from internet and for it, i'm using async download. The image is being downloaded, but it's not showing this image in my cell. I already tried to show in a normal view and it's working fine. It does work too if the image is already downloaded or if I roll the table view and show the cell again. Does anybody knows what's going on?
Code:
DownloadImageManager.m
-(id)initWithImageName:(NSString *)imageAddress{
self = [super initWithFrame:CGRectMake(10, 5, 100, 100)];
if (self){
self.urlString = imageAddress;
av = [[[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge] autorelease];
av.frame = self.frame;
[av setBackgroundColor:[UIColor greenColor]];
[self addSubview:av];
[av startAnimating];
[self checkImage];
}
return self;
}
-(void)checkImage{
bool isImageOnSysten = [self isImageOnFileSystem];
if (isImageOnSysten) {
//If image is on the system, loads the image, it's working fine here
NSLog(#"CSantos: isImageOnSysten %# is on system", self.urlString);
} else {
//here is the problem:
[self downloadImage];
}
}
-(void)downloadImage{
NSURL *url = [NSURL URLWithString:self.urlString];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request setAllowCompressedResponse:YES];
[request setQueuePriority:NSOperationQueuePriorityLow];
[request setDidFinishSelector:#selector(requestFinished:)];
[request setDidFailSelector:#selector(requestFailed:)];
[request setTimeOutSeconds:25];
[request setNumberOfTimesToRetryOnTimeout:3];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSData *responseData = [request responseData];
NSArray *words = [self.urlString componentsSeparatedByString:#"/"];
NSString *fileName = [words lastObject];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:fileName];
NSError *error = nil;
[responseData writeToFile:writablePath options:NSDataWritingAtomic error:&error];
NSLog(#"Write returned error: %#", [error localizedDescription]);
[av stopAnimating];
[av removeFromSuperview];
}
CellForProgram.m
- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) {
textLabel = [[UILabel alloc]initWithFrame:CGRectMake(60, 31, 235, 40)] ;
[self.contentView addSubview:textLabel];
photo = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, 70, 70)];
[photo setBackgroundColor:[UIColor blueColor]];
photo.image = imagePhoto.image;
[self.contentView addSubview:photo];
}
return self
Cell Caller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
CellForProgram *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier] ;
if (cell == nil) {
cell = [[[CellForProgram alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [speaker objectAtIndex:indexPath.row];
DownloadImageManager *imageManager = [[DownloadImageManager alloc] initWithImageName:[images objectAtIndex:indexPath.row]];
[cell.photo setImage:imageManager.image];
return cell;
}
You're not working with the pointers correctly.
When you call [cell.photo setImage:imageManager.image]; and the image does not exists, you're pointing it to nil or to an random memory space.
You need to create a pointer to your cell on the DownloadImageManager class, so that you can update the cell when the image finishes downloading.
Here's what I recommend:
Create a property on DownloadImageManager that points to your custom UITableViewCell class
Do not set the image on the tableView:cellForRowAtIndexPath: selector. Instead, set it directly on the DownloadImageManager.
Here's a simple modification to your code:
Cell Caller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
CellForProgram *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier] ;
if (cell == nil) {
cell = [[[CellForProgram alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [speaker objectAtIndex:indexPath.row];
DownloadImageManager *imageManager = [[DownloadImageManager alloc] initWithImageName:[images objectAtIndex:indexPath.row] andCell:cell];
return cell;
}
DownloadImageManager.m
-(id)initWithImageName:(NSString *)imageAddress andCell:(CellForProgram*)cell{
self = [super initWithFrame:CGRectMake(10, 5, 100, 100)];
if (self){
self.urlString = imageAddress;
self.cell = cell;
av = [[[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge] autorelease];
av.frame = self.frame;
[av setBackgroundColor:[UIColor greenColor]];
[self addSubview:av];
[av startAnimating];
[self checkImage];
}
return self;
}
-(void)checkImage{
bool isImageOnSysten = [self isImageOnFileSystem];
if (isImageOnSysten) {
//If image is on the system, loads the image, it's working fine here
NSLog(#"CSantos: isImageOnSysten %# is on system", self.urlString);
cell.photo = self.image;
} else {
//here is the problem:
[self downloadImage];
}
}
-(void)downloadImage{
NSURL *url = [NSURL URLWithString:self.urlString];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request setAllowCompressedResponse:YES];
[request setQueuePriority:NSOperationQueuePriorityLow];
[request setDidFinishSelector:#selector(requestFinished:)];
[request setDidFailSelector:#selector(requestFailed:)];
[request setTimeOutSeconds:25];
[request setNumberOfTimesToRetryOnTimeout:3];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSData *responseData = [request responseData];
NSArray *words = [self.urlString componentsSeparatedByString:#"/"];
NSString *fileName = [words lastObject];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:fileName];
NSError *error = nil;
[responseData writeToFile:writablePath options:NSDataWritingAtomic error:&error];
NSLog(#"Write returned error: %#", [error localizedDescription]);
[av stopAnimating];
[av removeFromSuperview];
cell.photo = self.image;
}
That should get you going. If you need any clarification, be sure to leave a comment and I'll answer shortly.
EDIT: As an alternative, implement an delegate method on the DownloadImageManager...
Add this to the DownloadImageManager.h:
#protocol DownloadImageManagerDelegate <NSObject>
#optional
- (void)DownloadFinished:(DownloadImageManager*)manager;
#end
Instead of the CellForProgram, use the DownloadImageManager protocol, with this constructor as example:
-(id)initWithImageName:(NSString *)imageAddress andDelegate:(DownloadImageManagerDelegate*)delegate
And change your implementation of requestFinished: like so:
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSData *responseData = [request responseData];
NSArray *words = [self.urlString componentsSeparatedByString:#"/"];
NSString *fileName = [words lastObject];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:fileName];
NSError *error = nil;
[responseData writeToFile:writablePath options:NSDataWritingAtomic error:&error];
NSLog(#"Write returned error: %#", [error localizedDescription]);
[av stopAnimating];
[av removeFromSuperview];
if ([delegate respondsToSelector:#selector(DownloadFinished:)]) {
[delegate DownloadFinished:self];
}
}
Then, make your cell implment the given protocol, like so:
- (void)DownloadFinished:(DownloadImageManager*)manager {
this.photo = manager.image;
}
This way you can keep your functionality on DownloadImageManager, as you want it.
I told I wouldn't need to do this kind of change on DownloadImageManager! But thanks for trying to help, it helped me in other stuff I was stucked!
CellForProgram.m
- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) {
textLabel = [[UILabel alloc]initWithFrame:CGRectMake(60, 31, 235, 40)] ;
[self.contentView addSubview:textLabel];
imagePhoto = [[DownloadImageManager alloc] initWithImageName:imageAdress.text];
[self.contentView addSubview:imagePhoto];
}
return self
}
DownLoadImageManager.m: add this method
-(void)changeImage:(NSString *)newImage{
self.urlString = newImage;
[self checkImage];
}
Cell Caller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
CellForProgram *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier] ;
if (cell == nil) {
cell = [[[CellForProgram alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [speaker objectAtIndex:indexPath.row];
[cell.imagePhoto changeImage:[images objectAtIndex:indexPath.row]];
return cell;
}