i have this function which call a function to check CMS for info. but the UIActivityIndicatorView freeze till the check is completed. not sure why.
EDIT: one thing funny, i commented out the performselector. the UIActivityIndicatorView still freezed. until i tapped my back button then it started to spin....
i'm using storyboard, iOS 5
-(void)showLoading
{
[activity startAnimating];
//loading is a label to show "File Loading"
loading.alpha =1;
//is a label to show a 0.3 alpha of the label
blackOverlay.hidden =0;
[self performSelector:#selector(updateFromInternet:) withObject:#"a" afterDelay:2];
//[self updateFromInternet:#"a"];
}
-(void)updateFromInternet:(NSString *)urlStr
{
NSString *URLString = #"http://sites.google.com/site/iphonesdktutorials/xml/Books.xml";
NSURL *updateDataURL = [NSURL URLWithString:URLString];
NSMutableURLRequest *WPXMLFetchRequest = [NSMutableURLRequest requestWithURL:updateDataURL];
self.receivedData = [NSMutableData data];
self.updateConnection = [NSURLConnection connectionWithRequest:WPXMLFetchRequest delegate:self];
NSLog(#"Checking update at : %#", updateDataURL);
//[self.updateConnection cancel];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
////NSlog(#"Receiving data");
[self.receivedData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
////NSlog(#"Failed to receive data");
self.receivedData = nil;
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
////NSlog(#"Received response from data");
[self.receivedData setLength:0];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *data=[[NSString alloc]initWithData:self.receivedData encoding:NSUTF8StringEncoding];
NSLog(#"data %#",data);
NSError *parseError = nil;
//NSDictionary *xmlDict = [XMLReader dictionaryForXMLData:self.receivedData error:&parseError];
self.receivedDict = [XMLReader dictionaryForXMLData:self.receivedData error:&parseError];
[self showDataOnScrollView];
}
You should delay the "heavy" function a bit and let the Activity Indicator fire.
try adding a 2.0 and not 2 to your delay (I would use a much smaller value - say 0.3)
[self performSelector:#selector(updateFromInternet:) withObject:#"a" afterDelay:0.3];
if this does not solve's your problem you should look (or post) the code related to the extra stuff you have in your code like : loading.alpha =1; and blackOverlay.hidden =0; which I assume are elements added to the Activity Indicator
Related
I am beginner of iPhone developer. I want to display data from server I have used below source code..
-(void)loadData:(id)sender
{
self.requestdata=[NSMutableData data];
NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:kLatestKivaLoansURL]];
[[NSURLConnection alloc]initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[requestdata setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[requestdata appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[connection release];
self.requestdata=nil;
}
#pragma mark-
#pragma process loan data
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[connection release];
NSString *responsedata=[[NSString alloc]initWithData:requestdata encoding:NSUTF8StringEncoding];
self.requestdata=nil;
NSDictionary *respDict = [[responsedata JSONValue]objectForKey:#"nodes"];
NSLog(#"Response Dict:%#",respDict);
NSMutableArray *arraY = [[NSMutableArray alloc]init];
arraY = [respDict mutableCopy];
NSLog(#"My array:%#",arraY);
NSString *mystr = [[[arraY objectAtIndex:0]valueForKey:#"node"]valueForKey:#"field_company_name_value"];
NSLog(#"Mystrname:%#",mystr);
NSArray *latestLoans=[(NSDictionary *)[responsedata JSONValue]objectForKey:#"responseData"];
NSLog(#"latest_dictionary:%#",latestLoans);
DisplayViewController *disp=[[DisplayViewController alloc]init];
for (int i = 0; i< [[latestLoans valueForKey:#"entries"] count] ; i++) {
// Search *aSearches = [[Search alloc] init];
NSDictionary *tempDict = [[latestLoans valueForKey:#"entries"] objectAtIndex:i];
// disp.link=[tempDict valueForKey:#"link"];
/*link = [tempDict valueForKey:#"link"];
aSearches.title = [tempDict valueForKey:#"title"];
aSearches.description = [tempDict valueForKey:#"contentSnippet"];
[appDelegate.search addObject:aSearches];*/
[appDelegate.disparray addObject:tempDict];
}
NSLog(#"DisplayArray:%#",appDelegate.disparray);
[self.view addSubview:disp.view];
/* DisplayViewController *disp=[[DisplayViewController alloc]initWithNibName:#"DisplayViewController" bundle:nil];
[self.navigationController pushViewController:disp animated:YES];*/
}
Please give any suggestion or source code which is apply in my code
Take a look at AFNetworking. It will do the job for you.
There is a specific method to handle JSON operations through the class AFJSONRequestOperation
Hope it helps.
http://www.touch-code-magazine.com/how-to-fetch-and-parse-json-by-using-data-models/
http://blog.zachwaugh.com/post/309924609/how-to-use-json-in-cocoaobjective-c
http://www.raywenderlich.com/5492/working-with-json-in-ios-5
http://json.org/
This is great tutorial for beginner, pls read this tutorial.
I am creating a single instance of a chase class which has a dictionary as a property.
As I add elements to dictionary, I can see the change in the count of dictionary keys.
But when I am accessing, it's firing a crash with message like given below:
[__NSCFString connection:didReceiveData:];
[__NSCFArray reqmap]; etc..
Basically, I am mapping request url with NSData instance, so that the response could be mapped and appended properly, asynchronously.
Code:
-(id)init
{
self = [super init];
if (self)
{
self.cacheDict = [[NSMutableDictionary alloc] initWithCapacity:20];
self.reqmap = [[NSMutableDictionary alloc] initWithCapacity:20];
}
return self;
}
+ (CommunityImageCache*)getSharedCommunityImageCache
{
if (sharedCommunityImageCacheInstance == nil) {
sharedCommunityImageCacheInstance = [[super allocWithZone:NULL] init];
}
return sharedCommunityImageCacheInstance;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSString* keyurl = [[[connection currentRequest] URL] absoluteString];
//crash point >>>>
NSMutableData* tempdata = (NSMutableData*)[self.reqmap objectForKey:keyurl];
[tempdata appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection
{
NSString* keyurl = [[[theConnection currentRequest] URL] absoluteString];
NSMutableData* tempdata = [self.reqmap objectForKey:keyurl];
UIImage* img = [UIImage imageWithData:tempdata];
[self.cacheDict setObject:img forKey:[#"image:\\\\public\\" stringByAppendingString:keyurl]];
[self.reqmap removeObjectForKey:keyurl];
}
-(UIImage *)getImageFromUrl:(NSString *)url
{
UIImage* image = nil;
image = [self.cacheDict objectForKey:url];
if (!image)
{
image = [UIImage imageNamed:#"defaultProfile.png"];
//dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSString* localUrl = [NSString stringWithString:url];
NSString* finurl = [localUrl substringFromIndex:[#"image:\\\\public\\" length]];
UIImage* img = nil;
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:finurl]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSMutableData* data = [[NSMutableData alloc] init];
NSURLConnection* connect = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
NSString* keyurl = [[[connect currentRequest] URL] absoluteString];
[self.reqmap setObject:data forKey:keyurl];
}
}
Needed badly, Thanks in advance.
Well, reqmap is suppose to contain NSMutableData objects, right ?
They need instantiation, something like :
[self.reqmap setValue:[[NSMutableData alloc] init] forKey:#"TheKey"];
You should also implement
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
when you're using NSURLConnection. I don't see it in your code above. Then you should alloc/reset the data in this function.
What is the actual error you are seeing? It sounds like either reqmap isn't an NSDictionary (though it is in your code above), or the object you're retrieving isn't a NSMutableData.
In total, implement:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
I am trying to add Loading data option in viewDidLoad() function before [self.tableview reloaddata]. I am not sure how to add it and is there a way to make the user know that there is data getting loaded.
I am parsing JSON file and the data gets loaded on 3G pretty slow, so its the better way to allow user to know that data is being loaded with loading option. Here is my code:
- (void)viewDidLoad {
[super viewDidLoad];
// Add the view controller's view to the window and display.
responseData = [[NSMutableData data] retain];
self.twitterArray = [NSMutableArray array];
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:#"http://search.twitter.com/search.json?q=mobtuts&rpp=5"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
[super viewWillAppear:animated];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSDictionary *results = [responseString JSONValue];
self.twitterArray = [results objectForKey:#"results"];
[self.tableView reloadData]; // How to add loading view before this statement
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [self.twitterArray count];
}
I'm not quite sure what you mean by "loading view" but i guess you mean an activity indicator or something else what should be presented while you are loading data.
make an ivar UIActivityIndicatorView *myLoadingView;
Init it in viewDidLoad
myLoadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
myLoadingView.hidesWhenStopped = YES;
[myLoadingView stopAnimating];
[self.view addSubView:myLoadingView];
show the view before you start your connection [myLoadingView startAnimating];
hide it again when the download was finished by stoping it in the delegate method connectionDidFinishLoading: after [self.tableView reloadData]; [myLoadingView stopAnimating];
release it in viewDidUnload [myLoadingView release];
Feel free to ask if you have questions or if i had misunderstood you.
From my ApplicationDelegate, I'm doing an NSURLConnection fetch over the network (it's wrapped in a class, as you'll see below). This one seems to work correctly: I get all the data in didReceiveData and I get the completion call connectionDidFinishLoading. At the end of connectionDidFinishLoading, I instantiate one or more of a slightly different kind of wrapper class, but they're essentially the same thing. The problem is that the second NSURLConnection's delegate is never having it's methods called.
I've looked at many different answers, but all to no avail. I'm not spawning any new threads and all the [NSThread isMainThread] checks I've littered throughout the code return true.
I'm stumped. Can anyone help me out? Here's the relevant code:
App Delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
ConnectionWrapper* w = [[ConnectionWrapper alloc] initWithParams:self
url:[NSURL URLWithString:<url>]];
[w beginFetch];
return YES;
}
...
-(void)fetchCompleted:(NSURL*)url directory:(NSString*)directory
{
NSLog(#"fetch completed");
}
-(void)fetchFailed:(NSURL*)url
{
NSLog(#"fetch failed");
}
...
ConnectionWrapper:
-(id)initWithParams:(id<ConnectionWrapperDelegate>)d url:(NSURL*)url
{
delegate = d;
connURL = url;
return [self init];
}
-(void)beginFetch
{
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:connURL];
NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[conn release];
[request release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"append");
[responseData appendData:data];
}
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
... parsing ....
DifferentConnectionWrapper* w = [[DifferentConnectionWrapper alloc] initWithParams:self
url:[NSURL URLWithString:<different url>]];
[w beginFetch];
}
-(void)fetchCompleted:(NSURL*)URL
{
NSLog(#"completed: %#", URL);
}
-(void)fetchFailed:(NSURL*)URL
{
NSLog(#"failed");
}
DifferentConnectionWrapper:
-(id)initWithParams:(id)d url:(NSURL*)url
{
delegate = d;
connURL = url;
return [self init];
}
-(void)beginFetch
{
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:connURL];
NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[conn release];
[request release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"append");
[responseData appendData:data];
}
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
... parsing ....
DifferentConnectionWrapper* w = [[DifferentConnectionWrapper alloc] initWithParams:self
url:[NSURL URLWithString:<different url>]];
[w beginFetch];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"got response");
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"got data");
[responseData appendData:data];
}
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
NSLog(#"image saver completed: %#", connURL);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"error");
}
ConnectionWrapper and DifferentConnectionWrapper have similar functions, but there's other logic that I've omitted here for brevity.
thanks for the help. I appreciate it.
A couple of things: I don't see a didFailWithError: in your first wrapper class, and (a little off topic) are you leaking memory with your DifferentConnectionWrapper *w ?
Anyway, what I would try is: see if you can invoke DifferentConnectionWrapper directly from the appDelegate instead of the ConnectionWrapper.
And I would try to decouple the two calls in any event. When the first one finishes, and calls appDelegate, can't you launch your DifferentConnectionWrapper from there?
I realize this doesn't explain your problem, but you might get it working (and which of THOSE two things is more important, is an entirely different debate.)
I believe the problem is that you’re releasing the URL connection in -beginFetch:
-(void)beginFetch
{
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:connURL];
NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[conn release];
[request release];
}
The URL connection object should be kept alive and released when the connection has finished loading:
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
... parsing ....
// *** Release the connection and whatever data you’ve kept related to
// this particular connection
[connection release];
[responseData release];
// *** or [responseData setLenght:0]; depending on how you’re
// managing responseData
DifferentConnectionWrapper* w = [[DifferentConnectionWrapper alloc] initWithParams:self
url:[NSURL URLWithString:<different url>]];
[w beginFetch];
}
or when there’s been an error:
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
// *** Release the connection and whatever data you’ve kept related to
// this particular connection
[connection release];
[responseData release];
// *** or [responseData setLenght:0]; depending on how you’re
// managing responseData
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
Edit: Your initialiser is a tad weird:
-(id)initWithParams:(id<ConnectionWrapperDelegate>)d url:(NSURL*)url
{
delegate = d;
connURL = url;
return [self init];
}
There’s no way to know what happens unless we see the code for -init and, at any rate, this should be the designated initialiser, so it shouldn’t be sending -init to self anyway. Furthermore, you should be retaining the url object that’s being passed to the initialiser.
The following makes more sense:
-(id)initWithParams:(id<ConnectionWrapperDelegate>)d url:(NSURL*)url
{
self = [super init];
if (self) {
delegate = d;
connURL = [url retain];
}
return self;
}
Don’t forget to release the url object in -dealloc or when you’re assigning another value to connURL.
OK. It turns out that this bug was caused by something I missed. I was going into a hard spin right after that second request, which would probably screw up just about anything. Once I fixed that problem, everything worked just fine.
Thanks for the help.
I have following code - methods to read XML files. But it works very slow for me. Isn't there any sufficient way to fetch and read data faster?
if(connectionRemaining)
{
[self LoadingPopUp];
NSURL *tmpURl=[NSURL URLWithString:[NSString stringWithFormat:#"%#getcategory.php",[iGolfAppDelegate getServerPath]]];
NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:tmpURl];
NSURLConnection *conn=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if(conn)
myWebData=[[NSMutableData data] retain];
connectionRemaining=NO;
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[myWebData setLength: 0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[myWebData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[connection release];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
// NSString *theXML = [[NSString alloc] initWithBytes: [myWebData mutableBytes] length:[myWebData length] encoding:NSUTF8StringEncoding];
// NSLog(#"%#",theXML);[theXML release];
if( myXMLParser )
[myXMLParser release];
myXMLParser = [[NSXMLParser alloc] initWithData: myWebData];
[myXMLParser setDelegate: self]; [myXMLParser setShouldResolveExternalEntities: YES];
[myXMLParser parse];[connection release];[myWebData release];
}
#pragma mark
#pragma mark XMLParsing Methods
-(void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict {
if([elementName isEqualToString:#"category"])
categoryArray=[[NSMutableArray alloc]init];
else if([elementName isEqualToString:#"Prop_Category"])
aCategory=[[Category alloc] init];
}
-(void)parser:(NSXMLParser*)parser foundCharacters:(NSString*)string {
if(!currentElementValue)
currentElementValue=[[NSMutableString alloc] initWithString:string];
else
[currentElementValue appendString:string];
}
-(void)parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName {
if([elementName isEqualToString:#"category"])
{ [LoadingAlert dismissWithClickedButtonIndex:0 animated:YES]; [LoadingAlert release];[self categoryPickerDiplay]; return; }
else if([elementName isEqualToString:#"Prop_Category"])
{ [categoryArray addObject:aCategory];[aCategory release];aCategory=nil; }
else{
[aCategory setValue:currentElementValue forKey:elementName];
[currentElementValue release];currentElementValue=nil;
}
}
Let me clarify my question again.
I have observed that this way of reading XML is not sufficient. By using this way iPhone loads data very slowly. Because, iPhone will read & compare each tag every time.
I want some faster XML loading & parsing.
There's an example from Apple called XMLPerformance that illustrates libxml vs. NSXMLParser in terms of performance. Check out its implementation of libxml.
The SiesmicXML and TopSongs code samples from adc show some ways of parsing XML that cause a minimum of user wait time.
Have you looked at the libxml C library, or the TouchXML wrapper for it? Also, are you sure that it's the NSXMLParser that's causing your slowdown? You might want to do a quick runthrough using Instruments or Shark to profile the application and find the hotspots.