SDWebImage with PHAssets - scroll

i have an application where i am loading large amount of images from database and showing them in my gallery, what i was doing earlier is i was getting photo url (local identifier) from PHAsset and then accessing the image using PHCacheManager, but it slows down my scrolling and also shows lags while updating images in new cell. I was trying to use SDWebImage here by passing the url to the sd_setImageWithURL: method, however i found out that the URL is actually a local identifier which is not supported by the method. Do we have other mechanism where i can use the identifier to load the images faster using SDWebImage or any other framework.
This is my code:
NSURL *photoURL = [NSURL URLWithString:photoPath];
[imageView sd_setImageWithURL:photoURL placeholderImage:defaultImage];
photoPath is the path to my asset "current image to be loaded"
i am getting the url something like:
73F05642-CAE6-49BE-879B-9B00BF15391F/L0/001
Please ask if more information is needed, i am new to iOS and all this stuff. Thanks in advance :)

it's late , but i am posting it so that it will be helpful for others .
SDWebImageManager * manager = [SDWebImageManager sharedManager];
[manager downloadImageWithURL:[NSURL URLWithString:localIdentifier] options:SDWebImageHighPriority targetLocalAssetSize:CGSizeMake(150, 150) progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (image) {
imageview.image = image;
}
}];

Related

LaunchServices: invalidationHandler called - iOS 8 share sheet

Seeing this error message in the logs, though not consistently, around the time that I use SLComposeViewController to open a Twitter or Facebook share sheet. I am not using any new iOS 8 API, just testing existing code on iOS 8. I see others have had this problem and even seen crashes when using other modal view controllers from the Cocoa Touch SDK.
LaunchServices: invalidationHandler called
Are there new precautions to take with SLComposeViewController and UIActivityViewController in iOS 8? Something else to consider?
Add this code after you present your activity view controller:
if ([activityVC respondsToSelector:#selector(popoverPresentationController)])
{
// iOS 8+
UIPopoverPresentationController *presentationController = [activityVC popoverPresentationController];
presentationController.sourceView = sender; // if button or change to self.view.
}
Looking at the developer forums: "That log message does not indicate any error on your part."
I had a similar problem with a UIDocumentInteractionController, where when I tapped outside it to dismiss it, or selected another app to open the document in, it would crash with the "LaunchServices: invalideationHandler called" console message displayed twice (only using iOS 8).
A workaround is to add the call to presentOpenInMenuFromRect:inView:animated to the main queue, i.e.
dispatch_async(dispatch_get_main_queue(), ^() {
[self.documentInteraction presentOpenInMenuFromRect:theRect inView:self.view animated:YES];
});
You may also need to define the sourceRect. I used the following code to display a SLComposeViewController from a tableView.
if ([controller respondsToSelector:#selector(popoverPresentationController)]) {
//get rect for this row in table
CGRect frame = [self.tableView rectForRowAtIndexPath:indexPath];
//convert table row frame to view reference
CGRect frameInView = [self.tableView convertRect:frame toView:self.view];
[controller popoverPresentationController].sourceRect = frameInView;
[controller popoverPresentationController].sourceView = self.view;
}
Regarding the auto-closing (not the crash):
I think it's probably related to the link you are trying to share. I'm seeing the same thing when trying to post music links (Spotify, SoundCloud,...). The same tweet works if I replace the link by a link to some non-media-content. I'll file radar on this to see whether it's intentional...
This gets rid of the Error message for me and works as expected. You have to get rid of the if statement that calls "isAvailableForServiceType:"
It should look like this. Happy coding.
SLComposeViewController *tweetSheet = [SLComposeViewController
composeViewControllerForServiceType:SLServiceTypeTwitter];
[tweetSheet setInitialText:#"Great fun to learn iOS programming at appcoda.com!"];
[self presentViewController:tweetSheet animated:YES completion:nil];
if ([tweetSheet respondsToSelector:#selector(popoverPresentationController)])
{
// iOS 8+
UIPopoverPresentationController *presentationController = [tweetSheet popoverPresentationController];
presentationController.sourceView = sender; // if button or change to self.view.
}

save images to core data using magical record

I'm using magical record with Core Data.
In my app I have just one entity with some string attributes. Now, I would like to add an image to this entity, but I don't have any idea of how to do that using magical record. I searched but haven't found anything on the web. In my app all the data is inserted by the user, so also the image, by the camera or the photo library.
How do I store images using Magical Record and Core Data?
Just store the image in the documents folder of the app and save a string with the file url in the core data entity.
What you're trying above can be done easily. Best advice i can give you is make a new sample project just to save and retrieve image from the CoreData database. That way you know exactly how the process works. If you try to embed this functionality in your current project you might loose track of what happening where.
This is very quick example, i'll expect you to import the Delegates in your .h files yourself etc.
First initiate the UIImagePicker via button
-(IBAction)pickImage:(id)sender
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
[self presentModalViewController:imagePicker animated:YES];
}
Once the image is selected, you can display it on the button using one of the delegate methods
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)selectedImage editingInfo:(NSDictionary *)editingInfo
self.imageButton.imageView.image = selectedImage;
To save it to CoreData assign your UIImage type to a Transformable type in your attribute in your database and then save the managedObjectContext
Links to help you:
UIImagePicker Class Reference
Magical Record Docs
CoreData Recipes Sample Project
Hope this help, good luck!
I found my answer:
to save:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString*nomeImmagine = [[NSString alloc] initWithFormat:#"%#", self.fieldName.text];
NSString *pngFilePath = [NSString stringWithFormat:#"%#/%#.png",documentsDirectory, nomeImmagine];
UIImage *image = self.showSelectedImage.image; // imageView is my image from camera
NSData *data1 = [NSData dataWithData:UIImagePNGRepresentation(image)];
[data1 writeToFile:pngFilePath atomically:NO];
to load:
-(void) loadImageFromPathInsideView
{
// [self loadImageFromPathInsideView];
Ricetta* contact =[[DataManager sharedClass]dammiTuttaLaRicetta:self.indice];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString*nomeImmagine = [[NSString alloc] initWithFormat:#"%#", contact.nome2];
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [NSString stringWithFormat:#"%#/%#.png",documentsDirectory, nomeImmagine];;
UIImage* image = [UIImage imageWithContentsOfFile:path];
self.image.image = image;
}
a word of advice. storing images as transformable (aka NSImage) type in core data is easy, but leads to overall slow app performance for even a low number (over 20) that range from 50k to 200kb with an average of 100k. even having those files linked via a relationship is slow, considering that one controller is often bound to another.
the above method of storing a local path name as a NSString pointing to Documents folder is heaps better for the overall experience.
that being said, creating a thumbnail image (of around 150x150) can be advantageous to create once and store that as a transient transformable NSImage, rather than loading the biggy and doing an on-the-fly resize a number of times. that performance can be observed easily scrolling up and down in a Table holding 50+ thumbnail images.

Trying to cache uiImages in dictionary, doesn't seem to affect loading time

I'm using a standard caching method to cache some UIImages loaded from the Documents directory. The images are being displayed in a UITableView. They're pretty large – the images themselves are up to 600x600 and are displayed in imageviews that are 240x180 (on a retina display, so the res discrepancy is not large).
Loading the images in realtime causes some lag when a new cell is about to come onscreen. So I've implemented a caching method in the object that handles the image:
- (UIImage *)imageWithStyle:(NSString *)styleName {
NSLog(#"looking for image %#", self.imageFileName);
/* if we have a cached image in dictionary, return it */
if (imageCache == nil) imageCache = [[NSMutableDictionary alloc] init];
UIImage *returnImage = [imageCache objectForKey:styleName];
if (returnImage != nil) {
NSLog(#"returning cached image");
return returnImage;
}
/* otherwise, look for image at path */
NSString *path = [self cacheFilePathWithStyle:styleName];
UIImage * originalImage = [[UIImage alloc] initWithContentsOfFile:path];
/* if image doesnt exist at path, start download and return nil */
if (originalImage == nil) {
NSLog(#"image not found. downloading.");
[self downloadImageFromS3];
return nil;
}
/* found image at path */
/* scale image for screen */
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)] && [[UIScreen mainScreen] scale] == 2){
returnImage = [UIImage imageWithCGImage:[[originalImage autorelease] CGImage] scale:2.0 orientation:UIImageOrientationUp];
NSLog(#"scaling image for retina");
} else {
returnImage = [originalImage autorelease];
NSLog(#"image scaled for standard resolution");
}
/* cache image in dictionary */
NSLog(#"caching image");
[imageCache setObject:returnImage forKey:styleName];
return returnImage;
}
Before the tableview appears on screen, I force all of the image handling objects to run this caching method to ensure that the images are present in the dictionary to be retrieved when they need to be displayed. By the NSLog's I can see that things are working as they should.
I'm getting lag-free performance now, but only after the image has appeared once on screen. So, when I initially see the tableview, I scroll down and the NSLogs tell me that the images are being retrieved from the cache, but still I get the same loading lag. After a cell has appeared on screen once, it thereafter loads up with no lag.
Is there something I'm missing here? Is there something more that I have to to to actually cache the image? Loading it and putting it in the dictionary doesn't seem to do the trick.
Thanks!
UPDATE
I've given up on this for now. There are some attempts out there to force the images to load by drawing them in a new context, but I'm not familiar with core graphics programming at this point. I've tried some code that folks have shared, but with no luck.
Instead, I'm going to display low-res versions of the images while the tableview is scrolling and load high-res versions when the tableview stops scrolling as announced through its delegate methods. At least I know this approach will work with any number of images.
From the documentation for -[UIImage initWithContentsOfFile:]:
This method loads the image data into memory and marks it as purgeable. If the data is purged and needs to be reloaded, the image object loads that data again from the specified path.
My guess is that, by loading all images into memory, your app consumes too much memory, causing the UIImage class to release the image data it can reload from files later.
If you use [UIImage imageNamed:], it'll do all this caching business for you. No need to roll your own cache and then wonder if it's working.
An upside and a downside to using that method. Upside: If you use the same image file twice, it won't actually load it twice, saving you that memory. Downside: Caching has a big memory impact, and you want to think pretty hard about doing it, whether you roll your own or not.

TTImageView refresh image

I have the following code
TTImageView* chart = [[[TTImageView alloc] initWithFrame:CGRectMake(2,2,30, 30)] autorelease];
chart.backgroundColor = [UIColor clearColor];
chart.defaultImage = nil;
chart.urlPath = #"http://test.com/test.png";
And I need to refresh the image, so I call reload function on the
chart. However the chart is not refreshed.
I found out that TTURLCache cached the image. So in app delegate when
app just started i do the following:
[TTURLCache sharedCache].disableImageCache = YES;
[[TTURLCache sharedCache] removeAll:YES];
However, the image is still not refreshed. Any help would be
appreciated. I also realized that whenever I do [chart reload], and check [chart isLoading] it is always true, which means that the request is not sent somehow.
Add a reload call after you set the URL and make sure you are calling from the main thread
[chart reload];
I ran into a similar issue when I tried loading my users avatars into a UIButton view. I needed to use TTImageView's delegate protocol to update the button's image. For example:
self.avatarImageView = [[TTImageView alloc] initWithFrame:CGRectMake(10, 10, 50, 50)];
self.avatarImageView.defaultImage = TTIMAGE(#"bundle://defaultAvatar.png");
self.avatarImageView.delegate = self;
self.avatarImageView.urlPath = #"http://www.site.com/path/to/image.png"
Once the urlPath is set, the request is made in the background. When you conform to the TTImageViewDelegate, you can access the following delegate methods.
/**
* Called when the image begins loading asynchronously.
*/
- (void)imageViewDidStartLoad:(TTImageView*)imageView {
NSLog(#"loading image...");
}
/**
* Called when the image finishes loading asynchronously.
*/
- (void)imageView:(TTImageView*)imageView didLoadImage:(UIImage*)image {
NSLog(#"loaded image!");
[self.avatarImageButton setImage:image forState:UIControlStateNormal];
}
/**
* Called when the image failed to load asynchronously.
* If error is nil then the request was cancelled.
*/
- (void)imageView:(TTImageView*)imageView didFailLoadWithError:(NSError*)error {
NSLog(#"error loading image - %#", error);
}
When the image has loaded successfully, I can use it for my UIButton as you'll see in the imageView:didLoadImage method.
Hope this helps shed some light on this issue. I know it's an old question, but maybe it'll help others later on.
After clearing the cache you should also reset the TTImageView. A simple way to do it would be to call [chart unsetImage] and then set the urlPath again.
Another way to do it without clearing the cache would be to add a dummy parameter to the url.
chart.urlPath = #"http://test.com/test.png?dummy=dummy";

how to get the path and url of the temp image?

I capture a image of webview that playing a flash. Because I want to show this image and use the IKSaveOptions to save the image .but I found the path of image is nil, Now I want to get the path of image , How to do ?
my code:
NSString *path = [[NSBundle mainBundle] pathForResource: ?? ofType:??];
NSURL *url = [NSURL fileURLWithPath: path];
then I use the url to show the image in the imageview,but Now I didn't get the path ,Thanks a lot!
thanks a lot. Now I think that the NSBundle is not my option. But I want to show the image of capturing it from a webview showing a flash. I can show it in a imagecell, but show in the imageview ,I use the code:
[imageView setImage:image imageProperties: mImageProperties];
and the mImageProperties come from ahead of the document of you take me the ImageKit documentation, the name is "Viewing an Image in an Image View" ,and in there the mImageProperties is the properties of image . code is :
mImageProperties = (NSDictionary*)CGImageSourceCopyPropertiesAtIndex(isr, 0, (CFDictionaryRef)mImageProperties);
still ues the url of the image, if I couldn't use the NsBundle , How I can do to get the properties of the image, by the way, I have already get the image of the capturing webview of showing a flash. code :
NSBitmapImageRep *imageRep = [webView bitmapImageRepForCachingDisplayInRect:[webView frame]];
[webView cacheDisplayInRect:[webView frame] toBitmapImageRep:imageRep];
NSImage *image = [[NSImage alloc] initWithSize:[webView frame].size];
[image addRepresentation:imageRep];
Okay, you are confusing a lot of things here. First off, IKSaveOptions does not save an imnage. It is a mechanism for presenting an interface to the user about the options the want for saving, but it does not actually save the file anywhere. To save the file you use the underlying CGImage mechanisms, as described in the ImnageKit documentation. I think if you read the example code there it will also be clear where the path to the saved file is.
Now, onto the second issue. You would never use pathForResource:ofType to get it. That gets resources that are in your application bundle. In other words, things that are a part of your application, that you include with it at build time. You should NEVER modify your bundle contents after build, aside from being complicated, it will invalidate codesigned applications. Instead you should probably use either CGImage or NSImage to read it in.
ok, I have the answer.
NSBitmapImageRep *imageRep = [webView bitmapImageRepForCachingDisplayInRect:tmpRect];
[webView cacheDisplayInRect:tmpRect toBitmapImageRep:imageRep];
NSImage *theimage = [[NSImage alloc] initWithSize:tmpRect.size];
[theimage addRepresentation:imageRep];
CGImageSourceRef isr = CGImageSourceCreateWithData((CFDataRef)[theimage TIFFRepresentation], NULL);
CGImageRef image = NULL;
if (isr)
{
image = CGImageSourceCreateImageAtIndex(isr, 0, NULL);
if (image)
{
mImageProperties = (NSDictionary*)CGImageSourceCopyPropertiesAtIndex(isr, 0, (CFDictionaryRef)mImageProperties);
}
CFRelease(isr);
}
if (image)
{
[imageView setImage:image imageProperties:mImageProperties];
CGImageRelease(image);
}

Resources