Building an app which gives the users the option to change the backgroud of the app.
Currently using this code to save images from the picker.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
customImage = [info objectForKey:UIImagePickerControllerOriginalImage];
NSData *data = UIImagePNGRepresentation(customImage);
NSString *fetchCustomImage = #"userCustomImage.png";
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
NSString *fullPathToFile = [documentDirectory stringByAppendingPathComponent:fetchCustomImage];
[data writeToFile:fullPathToFile atomically:YES];
[self dismissViewControllerAnimated:YES completion:NULL];
[self performSelector:#selector(fetchCustomBackground)]
}
Then calls a void to display the image
- (void)fetchCustomBackground
{
//Fetch Background Image
NSString *fetchUserImage = #"userCustomImage.png";
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
NSString *fullPath = [documentDirectory stringByAppendingPathComponent:fetchUserImage];
NSData *data = [NSData dataWithContentsOfFile:fullPath];
[background setImage:[UIImage imageWithData:data]];
}
In the viewDidLoad
[self performSelector:#selector(fetchCustomBackground)];
At the moment the app is very slow I guess because every time the view loads it has to fetch the image, is there a way to save it so you don't have to call it every time the view loads?
Try to update your function like this.
- (void)fetchCustomBackground
{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
__block NSData *data;
dispatch_sync(concurrentQueue, ^{
//Fetch Background Image
NSString *fetchUserImage = #"userCustomImage.png";
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
NSString *fullPath = [documentDirectory stringByAppendingPathComponent:fetchUserImage];
data = [NSData dataWithContentsOfFile:fullPath];
});
dispatch_sync(dispatch_get_main_queue(), ^{
[background setImage:[UIImage imageWithData:data]];
}); });
}
I see no problem with loading a a single picture from Documents. But for sure, if you are loading a large picture and doing simultanely some UI updates, it can be problem. You have to free main thread using Grand Central Dispatch.
Related
I am using the following code to download images. Can someone confirm the images are being downloaded asynchronously as they would appear to be? Normally, they download rapidly but every now and then the UI freezes for a minute while data comes through so something would appear to be awry:
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) //1
NSString *picURL = [NSString stringWithFormat:#"http://~/pics/%#",picname];
NSURL *urlPicUrl = [NSURL URLWithString:picURL];
dispatch_async(kBgQueue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:picURL]];
if (imgData) {
UIImage *imageCache = [[UIImage alloc] init];
imageCache = [UIImage imageWithData:imgData];
if (imageCache) {
[self saveImage:imageCache asPicName:picname];
dispatch_async(dispatch_get_main_queue(), ^{
});
}
}
});
EDIT:
Here is code to save image.
- (void)saveImage: (UIImage*)image asPicName: (NSString*)picname
{
if (image != nil)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithString: picname] ];
NSData* data = UIImagePNGRepresentation(image);
[data writeToFile:path atomically:YES];
}
}
I'm not quite sure whats going wrong here, I'd really appreciate some help as I'm very stuck.
This is my imagePickerController
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithLong:customphoto1] forKey:#"customphoto1count"];
UIImage *button1Image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
pngData = UIImagePNGRepresentation(button1Image);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"Button1image.png"]; //Add the file name
[pngData writeToFile:filePath atomically:YES]; //Write the file
[self dismissViewControllerAnimated:YES completion:NULL];
pngData = [NSData dataWithContentsOfFile:filePath];
UIImage *imageLoaded = [UIImage imageWithData:pngData];
[_button1 setImage:imageLoaded forState:UIControlStateNormal];
self.button1.clipsToBounds = YES;
self.button1.layer.cornerRadius = (self.button1.frame.size.width / 16);//half of the width
self.button1.layer.borderColor=[UIColor blackColor].CGColor;
self.button1.layer.borderWidth=1.0f;
[self dismissViewControllerAnimated:YES completion:NULL];
}
The above saves the image (as far as I believe) since _button1 is reading from imageLoaded
When the app closes and is reopened, this is the what calls the button to be displayed, and should load the picture from my NSData:
-(void)customButton1{
if (customphoto1 == 1) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"Button1image.png"]; //Add the file name
[pngData writeToFile:filePath atomically:YES];
pngData = [NSData dataWithContentsOfFile:filePath];
UIImage *imageLoaded1 = [UIImage imageWithData:pngData];
NSLog(#"%#", filePath);
// UIImage *imageload1 = [UIImage imageWithData:[newManagedObject valueForKey:#"imagesone"]];
[_button1 setImage:imageLoaded1 forState:UIControlStateNormal];
}
else {
button1ImageName = #"addnew";
}
}
Why is my image not loading?
Many thanks
Try this:
-(void)customButton1{
if (customphoto1 == 1) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"Button1image.png"];
UIImage *imageLoaded1 = [UIImage imagewithcontentsoffile:filePath];
NSLog(#"%#", filePath);
[_button1 setImage:imageLoaded1 forState:UIControlStateNormal];
}
else {
button1ImageName = #"addnew";
}
}
Debug: Check whether the filepath which is getting printed is correct or not. Open this path in Finder > CMD + Shift + G and paste the path (remove the file name from the path, use till folder level). Then check if that particular image is available in that folder or not.
Also in your didFinishPickingMediaWithInfo method, you are calling dismissViewControllerAnimated method two times, it should be once and at the end of method.
Hope this helps
Image was saving and loading alright all along - issue turned out to be with the buttons setImage function
I have UIImagePicker and UICollectionView in my view controller. I'am taking pictures and on 4th picture (it is also new line in collection view) application crashes due to "Memory Pressure". UIImagePicker delegate:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// Do picture get here
NSError *error;
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSData *imageData = UIImagePNGRepresentation(image);
NSNumber *imageNumber = [NSNumber numberWithInteger:[databaseManagementService selectTaskPictures].count];
NSString *imageName = [[imageNameDefault stringByAppendingString:[NSString stringWithFormat:objectFormat, imageNumber]] stringByAppendingString:extensionPNG];
// Do picture save to documents directory here
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:imageName];
[imageData writeToFile:savedImagePath atomically:NO];
// Do UIImagePicker dismiss here
[picker dismissViewControllerAnimated:YES completion:nil];
// Do picture details save to database here
TaskManagerTaskPicture *taskPicture = [[TaskManagerTaskPicture alloc] init];
taskPicture.filename = imageName;
taskPicture.id = imageNumber;
taskPicture.title = imageName;
taskPicture.pictureID = self.taskObject.id;
taskPicture.taskID = self.taskObject.id;
taskPicture.locationID = self.taskObject.location.id;
[databaseManagementService insertTaskPictureObject:taskPicture andError:&error];
// Do task picture update here
// Do task object SELECT here
self.taskObject = [databaseManagementService selectTaskWithID:self.taskObject.id];
// Do task picture objects retreive from task object here
self.taskPictureObjects = [self.taskObject.taskPicture allObjects];
// Do collection data reload here
[self.taskPicturesCollectionView reloadData];
}
Until now I have been debuting and realized that trouble is dousing by line:
NSData *imageData = UIImagePNGRepresentation(image);
Does anyone have any idea how to fix this issue?
Can you explain better the flow of your app?
However try implementing this code:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// Do picture get here
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSError *error;
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSData *imageData = UIImagePNGRepresentation(image);
NSNumber *imageNumber = [NSNumber numberWithInteger:[databaseManagementService selectTaskPictures].count];
NSString *imageName = [[imageNameDefault stringByAppendingString:[NSString stringWithFormat:objectFormat, imageNumber]] stringByAppendingString:extensionPNG];
// Do picture save to documents directory here
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:imageName];
[imageData writeToFile:savedImagePath atomically:YES];
dispatch_async(dispatch_get_main_queue(), ^{
// Do UIImagePicker dismiss here
[picker dismissViewControllerAnimated:YES completion:nil];
// Do picture details save to database here
TaskManagerTaskPicture *taskPicture = [[TaskManagerTaskPicture alloc] init];
taskPicture.filename = imageName;
taskPicture.id = imageNumber;
taskPicture.title = imageName;
taskPicture.pictureID = self.taskObject.id;
taskPicture.taskID = self.taskObject.id;
taskPicture.locationID = self.taskObject.location.id;
[databaseManagementService insertTaskPictureObject:taskPicture andError:&error];
// Do task picture update here
// Do task object SELECT here
self.taskObject = [databaseManagementService selectTaskWithID:self.taskObject.id];
// Do task picture objects retreive from task object here
self.taskPictureObjects = [self.taskObject.taskPicture allObjects];
// Do collection data reload here
[self.taskPicturesCollectionView reloadData];
});
});
}
In my application I grab an image from a picker and then try to display it in a separate view.
In my MainViewController.m I have
-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
{
[picker dismissViewControllerAnimated:YES completion:^ {
self.image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:UIImagePNGRepresentation(self.image) forKey:#"imageKey"];
[defaults synchronize];
PublishViewController *publish = [self.storyboard instantiateViewControllerWithIdentifier:#"Publish"];
[self presentViewController:publish animated:YES completion:nil];
}];
}
I then try to retrieve the image in my PublishViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSData *imageData = [[NSUserDefaults standardUserDefaults] objectForKey:#"imageKey"];
UIImage *userImage = [UIImage imageWithData:imageData];
self.image = [[UIImageView alloc] initWithImage:userImage];
}
The image does not show though. Any reason why?
Perhaps your -viewDidLoad in PublishViewController.m is called before the completion block in dismissViewControllerAnimated:completion: and the NSData has not been saved in NSUserDefaults, yet.
You could put the code to load self.image in PublishViewController.m into -ViewDidAppear.
Now that being said I agree with the commenters that NSUserDefaults may not be the best place to store the image data.
Rather than using NSUserDefaults, you are better using NSFileManager to save the image.
Within the pickerController Delegate methods of your MainViewController.m, place the following code -
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
[self dismissViewControllerAnimated:YES completion:nil];
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSData *imageData = UIImageJPEGRepresentation(image, 1);
//This code will save your image so you can retrieve it anywhere else within the app.
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentDirectory stringByAppendingPathComponent:#"yourImageName.jpg"];
[manager createFileAtPath:fullPath contents:imageData attributes:nil];
}
Where you can save the image name to whatever you like
Then within the viewDidLoad of your PublishViewController.m place this code to retrieve the image -
-(void)viewDidLoad{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:#"yourImageName.jpg"];
UIImage *retrievedImage = [UIImage imageWithContentsOfFile:fullPath];
self.yourImageView.image = retrievedImage;
}
Place a UIImageView on the view controller of your PublishViewController, which I've called yourImageView, for this example.
This will work for what you're looking for, hope it helps.
Thanks, Jim.
I am using below code to save and read saved clicked image file from document directory. Its working well for the first time but when i'm trying to read the saved image file for the second time, its showing me the image clicked during first time.
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingImage:(UIImage *)image
editingInfo:(NSDictionary *)editingInfo
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
#"test.png" ];
NSFileManager* fileManager=[NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:path]) {
NSError* error;
[fileManager removeItemAtPath:path error:&error];
}
NSData* data = UIImagePNGRepresentation(image);
[data writeToFile:path atomically:YES];
[self.viewController dismissViewControllerAnimated:YES completion:nil];
}
Any idea why every time its returning me image clicked for the first time.
didFinishPickingImage: is deprecated since iOS3.
This should work:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
if (!image) {
image = [info objectForKey:UIImagePickerControllerOriginalImage];
}
if (image) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:#"test.png" ];
NSData* data = UIImagePNGRepresentation(image);
[data writeToFile:path atomically:YES];
[self.viewController dismissViewControllerAnimated:YES completion:nil];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
Please check the documentation.