UIWebView loading - iphone

I want load the html data in webview. At the button click, it open the viewcontroller and load the html data in this viewcontroller (add web view in this view controller using Interface builder). When the html data not proper loading and i press the back button, at that time crash the app. i am not doing allocation & init webview in the coding. set IBOUTLET using Interface builder & bind it.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[connection release];
NSString *strResponce = [[NSString alloc] initWithData:jsonData_Info encoding:NSUTF8StringEncoding];
[jsonData_Info release];
NSError *error;
SBJSON *json = [[SBJSON new] autorelease];
self.jsonArray_Info=[json objectWithString:strResponce error:&error];
str_InfoDetail = [[self.jsonArray_Info objectAtIndex:0] valueForKey:#"Page"];
str_html = [NSString stringWithFormat:#"%#",str_InfoDetail];
NSString *temp;
temp = [NSString stringWithFormat:#"<html><head><style>body{background-color:transparent;}</style></head><body><span style='color:white'>%#</span></body></html>",str_html];
//web_Information = [[UIWebView alloc]init];
web_Information.backgroundColor=[UIColor clearColor];
web_Information.opaque= NO;
[web_Information loadHTMLString:temp baseURL:nil];
[act stopAnimating];
[strResponce release];
}
please give me any solution.
thanks.

Pls post some code and crash log if you need answers. By the look of it I think it may be because of implementation of UIWebView delegate in your class. I think when you navigate back you do not make the delegate nil which can cause the app to crash

Related

iphone memory issue while downloading images

I have a wierd problem. The requirement is to download image from a url on swipe and display it in image view .It is working all fine but I am getting memory warnings after 30 images and after few more swipe app crashes.
Implementation is pretty straight forward,but already spent almost 2 days to figure out the issue.
On each swipe i am calling A method :-
-(void)callDownloadImageAPI{
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
[self loadIndicator:#"Please Wait.!!" :#"Please be patient while we are downloading image for you"];
#try{
DownloadImage *downLoadImge =[[DownloadImage alloc] init];
downLoadImge.delegate=self;
[downLoadImge getImage:[self.allUrlArray objectAtIndex:self.initialImageViewCounter]];
}
#catch (NSException *e) {
NSLog(#"callDownloadImageAPI exception %#",[e description]);
[HUD hide:YES];
}
[pool release];
}
This method download 1 image at a time and send UIImage to its delegate
//Implementation of DownloadImage.h and .m
#protocol DownloadImageDelegate
#required
- (void)messageFormServerWithImage:(UIImage*)imageFromSever;
- (void)gettingImageFailed :(NSString*)errorDesc;
#end
#interface DownloadImage : NSObject
#property(strong) NSURLConnection* connection;
#property(weak) id<DownloadImageDelegate> delegate;
#property(strong) NSMutableData* data;
-(void)getImage:(NSString *)imageUrl;
//DownloadImage.m
-(void)getImage:(NSString *)imageUrl{
#autoreleasepool {
[[NSURLCache sharedURLCache] removeAllCachedResponses];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageUrl]cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
#autoreleasepool {
NSLog(#"connectionDidFinishLoading");
self.connection=nil;
if( self.data == nil) {
return;
}
// NSString* jsonStr = [[NSString alloc] initWithData:self.data encoding:NSASCIIStringEncoding];
UIImage *img=[UIImage imageWithData:self.data];
// NSArray *messages_json = [parser objectWithString:jsonStr error:nil];
[self.delegate messageFormServerWithImage:img];
self.data = nil;
img= nil;
}
}
Other delegates of NSUrlConnections are implemented but I am not putting it here .
Once this image is returned i am setting this image to scrollview and displaying it and deleting the previous image from scrollview.
More Info:-
Just to verify i commented out setting image to scrollview and just downloaded images on each swipe but still it crashes around 30 images
Surprisingly I am using same class DownloadImage.h and .m to download image at other places in the same work and it work awesome even with 500images .
I am testing in iPod Touch and I checked the memory utilised remain between 12-14mb(never exceed this)
Please help me out guys,let me know if you need more detail.
Its crashing because all the images are being stored in virtual memory, you need to be caching them and then loading them back into memory when the user actually views them.
Try also setting your image objects to nil after they have been cached or are not needed.
In your class I would also recommend using the didReceiveMemoryWarning method and release some of your images from memory when this is called.

iPhone - Make UITableViewCells appear on view load before NSURLConnection completes

I am trying to create a loose version of LazyTabelImages using storyboard and JSON. in ViewDidLoad on my main TableViewController, I start an NSURLConnection to get the JSON data, but my cells do not load until after the connection is completed. I want the same behavior that LazyTableImages has, where the cells load as blanks, but then have the information filled in (reload the table data). I can duplicate this if I do not use storyboard, as LazyTables does not use storyboard, but that is not an option.
I have looked through LazyTableImages to try to find the solution, but storyboard make a big difference (to me anyway).
Is there a simple way to get the cells to load as blanks? For example, if the device has no internet, I still want my TableView to show up, and I will put a custom message in the cell.
Code:
The part of my viewDidLoad where I initialize the connection....
NSURLRequest *urlrequest = [NSURLRequest requestWithURL:[NSURL URLWithString:serverURL]];
self.dataConnection = [[NSURLConnection alloc] initWithRequest:urlrequest delegate:self];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
connectionDidFinnishLoading...
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//ListData below is an array that my data received (JSON) is loaded into. It is then passed to getTableData.
self.dataConnection = nil;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self performSelectorOnMainThread:#selector(getTableData:) withObject:ListData waitUntilDone:YES];
});
}
getTableData...
-(void)getTableData:(NSData *)jsonData
{
NSError *error = nil;
arrayEntries = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:&error];
for (int x = 0; x < arrayEntries.count; x++)
{
NSMutableDictionary *dic = [arrayEntries objectAtIndex:x];
//ARecord is a class just like in LazyTableImages that creates objects to keep the icons/data together. The ARecords are loaded into the TableView
ARecord *arecord = [[ARecord alloc] init];
NSString *title = [dic objectForKey:#"title"];
NSString *subt = [dic objectForKey:#"subtitle"];
NSString *url = [dic objectForKey:#"image_URL"];
arecord.Icon = nil;
arecord.URL = url;
arecord.Name = title;
arecord.title = subt;
//this is where I load an array full of the arecord objects.
[array addObject:arecord];
}
[self.tableView reloadData];
}
I've done something similar. In viewDidLoad: I set the array for table data to a few objects of [NSNull null] for however many blank rows I want to show while the data is downloading. In cellForRowAtIndexPath: I check if [self.arrayOfTableData objectAtIndex:indexPath.row] = [NSNull null]. If so return a "blank" cell, otherwise load the cell with ARRecrod data.
Then when the URL completes, replace the array of NSNulls with array of your ARRecords.
I do this with two objects. First, I have an image fetcher class that downloads data asynchronously and notifies a delegate when it's complete. Then I have an image view class that implements the fetcher's delegate methods. So something like:
#implementation AsyncImageFetcher
-(id)initWithURL:(NSURL *)aURL andDelegate:(id<SomeProtocol>)aDelegate{
//...
NSURLRequest *req = [NSURLRequest requestWithURL:aURL];
//Note that NSURLConnection retains its delegate until the connection
//terminates! See comments in MyImageView below.
[NSURLConnection connectionWithRequest:req delegate:self];
//...
}
//Implement standard connection delegates here. The important part is:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
// ...
UIImage *anImage = [self decodeDownloadedDataIntoAnImage];
if([[self delegate] respondsToSelector:#selector(imageFetcher:didFetchImage:)]){
[[self delegate] imageFetcher:self didFetchImage:anImage];
}
//...
}
#end
Then I subclass UIImageView or UIView or something (depending on how flexible you need to be) to implement the delegate protocol and fire off the fetcher:
#implementation MyImageView
-(id)initWithURL:(NSURL *)aURL andPlaceHolderImage:(UIImage *)aPlaceHolder{
//...
[self setImage:aPlaceHolder];
//Note we don't assign this to an ivar or retain it or anything.
//That's ok because the NSURLConnection inside the fetcher actually
//retains the fetcher itself. So it will live until the connection
//terminates -- which is exactly what we want. Thus we disable
//CLANG's noisy warnings.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-value"
[[AsyncImageFetcher alloc] initWithURL:aURL andDelegate:self];
#pragma clang diagnostic pop
return self;
}
-(void)imageFetcher:(MCMAsyncImageFetcher *)anImageFetcher didFetchImage:(UIImage *)anImage{
[self setImage:anImage];
}
#end
In your specific case, you'd just set a MyImageView as your cell's imageView in -tableView:cellForRowAtIndexPath:, passing reasonable values for its placeholder and URL, of course.
Since I haven't see your code, I just give my suggestion here:
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_queue_t queue = dispatch_queue_create(NULL, NULL);
dispatch_async(queue, ^{
//add your connection code here
//parse the json and store the data
//
dispatch_async(dispatch_get_main_queue(), ^{
//here to reload your table view again,
//since UI related method should run on main thread.
[YOUR_TABLEVIEW reloadData];
});
});
[YOUR_TABLEVIEW reloadData];
}
Note: Make sure your tableview in storyboard has connected to that in code! Hope it helps!

reload json data to UITableView

I'm a bit confused. I have 2 classes, an app delegate and a view controller. In my app delegate I get some data via this method:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSDictionary *results = [responseString JSONValue];
NSArray *allTweets = [results objectForKey:#"results"];
[viewController setTweets:allTweets];
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
and in my view controller I have a button that should reload the data...I've tried a few things such as
Twitter_SearchAppDelegate *appDelegate= (Twitter_SearchAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate connectionDidFinishLoading];
but none worked...am I going about this in the wrong way? I just want to be able to call the method that loads the data in the first place from the app delegate to the view controller.
Any help is appreciated!
Yes, you are going in the wrong direction.
You are trying to call the NSURLConnection delegate method your self (wrong).
If you want to simply reload the JSON data, you should call in your App Delegates method that initiates the download request to force in the data reload!
first of all , if i'm not wrong , connectionDidFinishLoading is a delegate method which is triggered when you start the connection process.
have you test that your application enters connectionDidFinishLoading ?
in addition when you evaluate your array/dictionary as source to your tableview , did you call again ["your-table-view-name" reloadData] ?
hope this helps..

Programmatically tap on HTML href in order to update app

I'm planning updates for an enterprise app with ad-hoc distribution.
For updates, Apple recommends having the user visit an HTML page and tap on a link:
href="itms-services://?action=download-manifest&url=http://example.com/
manifest.plist"
See http://help.apple.com/iosdeployment-apps/#app43ad871e
I don't want to do this. I want the app to programmatically check for updates on launch and alert the user with a UIAlertView that an update is available.
Here's what I have so far in application didFinishLaunching. The complicated plist parsing comes from the structure of an example plist found here: http://help.apple.com/iosdeployment-apps/#app43ad78b3
NSLog(#"checking for update");
NSData *plistData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://example.com/MyApp.plist"]];
if (plistData) {
NSLog(#"finished checking for update");
NSError *error;
NSPropertyListFormat format;
NSDictionary *plist = [NSPropertyListSerialization propertyListWithData:plistData options:NSPropertyListImmutable format:&format error:&error];
if (plist) {
NSArray *items = [plist valueForKey:#"items"];
NSDictionary *dictionary;
if ([items count] > 0) {
dictionary = [items objectAtIndex:0];
}
NSDictionary *metaData = [dictionary objectForKey:#"metadata"];
float currentVersion = [[[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"] floatValue];
float newVersion = [[metaData objectForKey:#"bundle-version"] floatValue];
NSLog(#"newVersion: %f, currentVersion: %f", newVersion, currentVersion);
if (newVersion > currentVersion) {
NSLog(#"A new update is available");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Update available" message:#"A new update is available." delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"UPDATE", nil];
[alert show];
}
}
}
Then I have my UIAlertView delegate method:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1) {
NSLog(#"downloading full update");
UIWebView *webView = [[UIWebView alloc] init];
[webView loadRequest:[[NSURLRequest alloc] initWithURL:[NSURL URLWithString:#"itms-services://?action=download-manifest&url=http://example.com/MyApp.plist"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0]];
}
}
A few things:
I know [alert show] shouldn't be called in application didFinish, but I'll change it later.
I don't know how quickly plistData will be downloaded and how this download affects the app.
More importantly, my alert view delegate method doesn't work, and the update doesn't download. Even when I introduce webView with #property (nonatomic, strong) UIWebView *webView, the method doesn't do anything.
I think Dropbox has the MIME configured properly because I can download the .ipa through google Chrome.
So what I really need is a way using NSURLConnection (NSURLRequest etc.) to replicate the act of a user tapping on an HTML href. After that I think the full update will occur.
You can open a URL automatically using
[[UIApplication sharedApplication] openURL:...];
I don't know if it works for itms-services: urls, but it works for other bespoke URL schemes like tel:, fb: etc. so it should do unless Apple have specifically blocked it.

Issue with loading view and web service synchronous call

I am using iPhone to get data from my web service.
Because I wan't to display loading view while getting data I invoke web service synchronous.
I have button which navigate to table view (that get data from ws):
Loading *loading = [[Loading alloc]init];
[[[UIApplication sharedApplication] keyWindow] addSubview:loading.view];
TableViewController *tableViewController = [[TableViewController alloc] init];
[self.navigationController pushViewController:tableViewController animated:YES];
[loading.view removeFromSuperview];
And I call web service in viewDidLoad of my view.
webData = [NSURLConnection sendSynchronousRequest:req
returningResponse:&response
error:&error];
NSString *xml= [[NSString alloc] initWithBytes:[webData mutableBytes]
length:[webData length]
encoding:NSUTF8StringEncoding];
// Parse XML etc.
I have tried to add loading view before I call web service (in viewDidLoad) but still doesn't work.
Any idea how to display loading view?
You should call the web service asynchronously. By doing it synchronously, you are blocking the main (UI) thread & it can't finish loading your view or make it appear (or animate things on the loading view), etc.