Trouble Displaying Images On Device - ios

I'm working on my first IOS app. The app downloads and displays data from a database via a PHP web page. That's all working fine. I also grab an image from the same web server to display in a UIImageView. This all works on fine on the Simulator.
On my test device (a 3GS), everything works except I cannot get the downloaded image to display in my UIImageView.
If there is no internet connection, I am able to display my alternate image that I've included in app's bundle on the simulator and on the device.
// Inside My data class Implementation
- (void)setUpTheData
{
--- other code ---
NSURL *myImageURL = [NSURL URLWithString:myImageURLString];
NSData *myImageRawData = [NSData dataWithContentsOfURL:myImageURL];
self.myImageData = myImageRawData;
}
- (NSData*)getTheImageData
{
return _myImageData;
}
// Inside my viewDidLoad
UIImage *theImage = [UIImage imageWithData:[theRemoteData getTheImageData]];
_testImage.image = theImage;
I've compared the image data from both the simulator and the device and they are the same.

Try viewDidAppear instead of viewDidLoad maybe?

I had set a weak pointer in my imageData property in my data class. Changing to strong fixed my problem.

Related

UIImageView displays downloaded images from HTTP, but won't display image resource

In my first View Controller after a user logs in, there is a quick check to see if the user has uploaded a custom image to his account. (If he has, there's a URL in the user's profile data.)
These images are downloaded correctly in my code and they show up beautifully. The problem comes when there is no custom user image, and the VC tries to set the same UIImageView to a default picture (in xcassets). The picture is being loaded into the bundle, as far as I can tell, and it's a valid PNG file.
Here is the snippet for setting the image. If a custom URL is not found, I set the URL parameter string to "nil."
-(void) setImageWithUrl: (NSString *) Url Imageview: (UIImageView *) image {
if (Url.length > 4) {
NSURL *url = [NSURL URLWithString:Url];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *Profileimage = [UIImage imageWithData:data];
[image setImage:Profileimage];
}
else {
UIImage *Profileimage = [UIImage imageNamed:#"DefaultPicture"];
[image setImage:Profileimage];
}
}
This one's driving me nuts, so all weird ideas are welcome. :-)
Let me know if you want me to post any other parts of the code that you think could be a factor.
It looks like debug-need issue. But why don't you use any image download/cache library, like SDWebImage?
It gonna be much efficient and convenient

Titanium Appcelerator - Remote URL not showing up as background image to View

So here's a nice one. I'm creating a imageView by doing this:
var tagView = Titanium.UI.createImageView({
backgroundImage: 'http://www.travelandtourworld.com/wp-content/uploads/2013/07/google-logo.jpg',
height:150,
width:365,
zIndex:10000
});
The problem is - anytime I use a remote URL as a background image it doesn't show up. Has anyone run into this and is there a good workaround for it?
It's just a rough guess but does it work when you use a normal View instead of an ImageView? Or try the image-property instead of backgroundImage-property for the ImageView. I just think that a background image is not the best practice to do on an ImageView even though the docs say it's possible.
I've done some testing with this as well and also found that backgroundImage doesn't work for remote URLs.
I've sort of fixed it by hacking this code into TiUtils.m of the Appcelerator core (tested with 3.5.0.GA).
if (resultImage == nil) {
if ([image isKindOfClass:[NSString class]]) {
NSURL* imageURL = [TiUtils toURL:image relativeToURL:nil];
resultImage = [[ImageLoader sharedLoader] loadRemote:imageURL];
}
}

Screenshot Safari from Share Extension

Is it possible to perform a screenshot of the current visible zone of the webview in Safari from a Share Extension? I could use windows, but UIApplication isn't supported on extensions so I can't access to that window.
You can't since UIApplication can't be reached from an extension. You cannot get the first UIWindow, which is the Safari layer, so you have to play with the Javascript preprocessing file that the extensions have. So just create a Javascript file that, when sent to Safari, generates a base64 string with the current visible zone image data. Take that string through the kUTTypePropertyList identifier in your extension. Since that should be NSData, generate the UIImage from there, by using +imageWithData. That is what you're looking for, without having to load the page again, preventing a second load and a bad image if the webpage requires of a login.
As far as I know, you can't unless you invoke the API you need dynamically, and even so you might run into context permission issues and app store approval issues.
An alternative might be passing the current Safari URL to your extension, load it using a hidden UIWebView and render this view into an UIImage but you will loose the current visible zone information...
Edit: So the below works in the Simulator but does not work on the device. I'm presently looking for a solution as well.
You can't get just the visible area of Safari, but you can get a screenshot with a little ingenuity. The following method captures a screenshot from a ShareViewController.
func captureScreen() -> UIImage
{
// Get the "screenshot" view.
let view = UIScreen.mainScreen().snapshotViewAfterScreenUpdates(false)
// Add the screenshot view as a subview of the ShareViewController's view.
self.view.addSubview(view);
// Now screenshot *this* view.
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, false, 0);
self.view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Finally, remove the subview.
view.removeFromSuperview()
return image
}
This is the approved way to capture the screenshot of a webpage in a share extension:
for (NSExtensionItem *item in self.extensionContext.inputItems) {
for (NSItemProvider *itemProvider in item.attachments) {
[itemProvider loadPreviewImageWithOptions:#{NSItemProviderPreferredImageSizeKey: [NSValue valueWithCGSize:CGSizeMake(60.0f, 60.0f)]} completionHandler:^(UIImage * item, NSError * _Null_unspecified error) {
// Set the size to that desired, however,
// Note that the image 'item' returns will not necessarily by the size that you requested, so code should handle that case.
// Use the UIImage however you wish here.
}];
}
}

UITableView On Screen Image Download Lazy Loading

First of all this is not a duplicate. I have seen some identical questions but they didn't help me as my problem varies a little bit.
Using the following code i am download the images asynchronously in my project.
{
NSURL *imageURL = [NSURL URLWithString:imageURLString];
[self downloadThumbnails:imageURL];
}
- (void) downloadThumbnails:(NSURL *)finalUrl
{
dispatch_group_async(((RSSChannel *)self.parentParserDelegate).imageDownloadGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *tempData = [NSData dataWithContentsOfURL:finalUrl];
dispatch_async(dispatch_get_main_queue(), ^{
thumbnail = [UIImage imageWithData:tempData];
});
});
}
Due to the logic of the program, i have used the above code in files other than the tableview controller which is showing all the data after getting it from the web service.
PROBLEM: On screen images does not show up until i scroll. The off screen images are refreshed first. What can i do to solve my problem.
Apple's lazy loading project is using scrollViewDidEndDragging and scrollViewDidEndDecelerating to load the images but the project is way too big to understand plus my code is in files other than the tableview controller.
NOTE: Kindly do not recommend third party libraries like SDWebImage etc.
UPDATE: As most of people are unable to get the problem, i must clarify that this problem is not associated with downloading, caching and re-loading the images in tableview. So kindly do not recommend third party libraries. The problem is that images are only showing when the user scrolls the tableview instead of loading the on screen ones.
Thanks in advance
I think what you have to do is:
display some placeholder image in your table cell while the image is being downloaded (otherwise your table will look empty);
when the downloaded image is there, send a refresh message to your table.
For 2, you have two approaches:
easy one: send reloadData to your table view (and check performance of your app);
send your table view the message:
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
Using reloadRowsAtIndexPaths is much better, but it will require you to keep track of which image is associated to which table row.
Keep in mind that if you use Core Data to store your images, then this workflow would be made much much easier by integrating NSFetchedResultController with your table view. See here for an example.
Again another approach would be using KVO:
declare this observe method in ItemsViewCell:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if ([keyPath isEqual:#"thumbnail"]) {
UIImage* newImage = [change objectForKey:NSKeyValueChangeNewKey];
if (newImage != (id)[NSNull null]) {
self.thumbContainer.image = newImage;
[self.thumbContainer setNeedsLayout];
}
}
}
then, when you configure the cell do:
RSSItem *item = [[channel items] objectAtIndex:[indexPath row]];
cell.titleLabel.text = [item title];
cell.thumbContainer.image = [item thumbnail];
[item addObserver:cell forKeyPath:#"thumbnail" options:NSKeyValueObservingOptionNew context:NULL];
By doing this, cell will be notified whenever the given item "thumbnail" keypath changes.
Another necessary change is doing the assignment like this:
self.thumbnail = [UIImage imageWithData:tempData];
(i.e., using self.).
ANOTHER EDIT:
I wanted to download and load the images just like in the LazyTableImages example by Apple. When its not decelerating and dragging, then only onscreen images are loaded, not all images are loaded at once.
I suspect we are talking different problems here.
I thought your issue here was that the downloaded images were not displayed correctly (if you do not scroll the table). This is what I understand from your question and my suggestion fixes that issue.
As to lazy loading, there is some kind of mismatch between what you are doing (downloading the whole feed and then archiving it as a whole) and what you would like (lazy loading). The two things do not match together, so you should rethink what you are doing.
Besides this, if you want lazy loading of images, you could follow these steps:
do not load the image in parser:foundCDATA:, just store the image URL;
start downloading the image in tableView:cellForRowAtIndexPath: (if you know the URL, you can use dataWithContentOfURL as you are doing on a separate thread);
the code I posted above will make the table update when the image is there;
at first, do not worry about scrolling/dragging, just make 1-2-3 work;
once it works, use the scrolling/dragging delegate to prevent the image from being downloaded (point 2) during scrolling/dragging; you can add a flag to your table view and make tableView:cellForRowAtIndexPath: download the image only if the flag says "no scrolling/dragging".
I hope this is enough for you to get to the end result. I will not write code for this, since it is pretty trivial.
PS: if you lazy load the images, your feed will be stored on disk without the images; you could as well remove the CGD group and CGD wait. as I said, there is not way out of this: you cannot do lazy loading and at the same time archive the images with the feed (unless each time you get a new image you archive the whole feed). you should find another way to cache the images.
Try using SDWebImage, it's great for using images from the web in UITableViews and handles most of the work for you.
The best idea is caching the image and use them. I have written the code for table view.
Image on top of Cell
It is a great solution.
Try downloading images using this code,
- (void) downloadThumbnails:(NSURL *)finalUrl
{
NSURLRequest* request = [NSURLRequest requestWithURL:finalUrl];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data, NSError * error)
{
if (!error)
{
thumbnail = [UIImage imageWithData:data];
}
}];
}

Memory Leak Downloading image from server

I have a paged slider view with an image on each page. I'm using NSOperationQueue to help me download the images from the server while the program is running. The NSOperationQueue is used to call the following method,
-(NSData *)imageWith:(NSString *)imageName
{
NSString *imagePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:imageName];
NSData *imageData = [NSData dataWithContentsOfFile:imagePath];
if (!imageData) {
imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[[NSString stringWithFormat:#"%#/%#", picsURL,imageName] stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]]];
if (imageData) {
[imageData writeToFile:imagePath atomically:YES];
}
}
return imageData;
}
and then I use the main thread to display the downloaded image on the scrollerview:
[self performSelectorOnMainThread:#selector(loadPic:) withObject:[NSArray arrayWithObjects:[self imageWith:[picsNames objectAtIndex:imageView.tag]], [NSString stringWithFormat:#"%d", imageView.tag], nil] waitUntilDone:YES];
which calls the following method:
-(void)loadPic:(NSArray *)imageAndTagArray
{
if (imageAndTagArray.count) {
//loading the image to imageview
UIImageView *imageView = (UIImageView *)[scrollView viewWithTag:[[imageAndTagArray objectAtIndex:1] intValue]];
imageView.image = [UIImage imageWithData:((NSData *)[imageAndTagArray objectAtIndex:0])];
//stopping the indicator
[((UIActivityIndicatorView *)[imageView viewWithTag:ACTIVITY_INDICATOR_TAG]) stopAnimating];
}
}
Everything works fine for the first 60 images, but after that I receive a Memory Warning and after about 100 images the app crashes.
I have been spending so much time on this and I can't figure out what to do. I've used Instruments and it doesn't detect any leak. I've also used Analyze and that did show anything either.
EDIT:
If I replace the imageWith: method definition with the following definition I still get the warnings, where 5.jpg is a local image.
-(NSData *)imageWith:(NSString *)imageName
{
return UIImagePNGRepresentation([UIImage imageNamed:#"5.jpg"]);
}
Let me tell you more about the situation.
When the app starts I have a view with a paged scrollview inside it that contains 9 images per page. the scrollview uses the nsoperationqueue to load images which calls the imageWith: method.
when the user taps on any of the images a second view opens with a full display of the selected image. this second view also has a scroll view that contains the same images as the first view but with full display, meaning 1 image per page.
when you are on the second view and scrolling back and forth the app crashes after loading about 60 images.
It also crashes if say it loads 50 images and then you tap on the back button and go to the first view and then tap on another image and go to the second view and load about 10 images.
It sounds like you're holding too many images in memory. When you open the second view, it's reloading the images again from disk, until you end up with two copies of all the images.
The UIImage class may be able to help you with this memory management. In its reference page, it mentions that it has the capability to purge its data in low-memory situations and then reload the file from disk when it needs to be drawn again. This might be your solution.
However, as you're creating the image from an NSData read from disk, the UIImage will probably not be able to purge its memory - it won't know that your image is simply stored on the disk, so it can't throw away the data and reload it later.
Try changing your "imageWith" method to create a UIImage (via imageWithContentsOfFile) from the file URL on the disk just before it returns, and return the UIImage rather than returning the intermediate NSData. That way, the UIImage will know where on disk its image source came from and be able to intelligently purge/reload it as memory becomes constrained on the device.

Resources