Benefits of using Setter and Getter methods vs. direct manipulation - ios

Sorry if this a beginner question but I was wondering what the benefits are to using setter and getter methods rather than directly manipulating them directly. I'm in obj-c and I'm wondering if there is any benefits in terms of memory/cpu usage.
For instance, I'm cropping an image before I upload it and I crop it after it is taken/picked. I put all my code in the didFinishPickingMediaWithInfo method. So it would look like the following:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
//Create image
imageFile = [info objectForKey:UIImagePickerControllerOriginalImage];
//Unhide imageView and populate
selectedImage.hidden = false;
selectedImage.image = imageFile;
//Create original image for reservation
originalImage = imageFile;
//Crop image
UIGraphicsBeginImageContext(selectedImage.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextRotateCTM(context, 2*M_PI);
[selectedImage.layer renderInContext:context];
imageFile = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//Update imageView with croppedImage
selectedImage.image = imageFile;
//Dismiss image picker
[imagePickerController dismissViewControllerAnimated:YES completion:nil];
}
So let's say I do the same thing but have a method for populating the selectedImage imageView and a method for cropping the image so it would look like the following:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
//Create image
[self setImage:[info objectForKey:UIImagePickerControllerOriginalImage]];
//Create local image
UIImage * localImage = [self returnImage];
//Unhide imageView and populate
selectedImage.hidden = false;
[self populateImageView:localImage];
//Create original image for reservation
originalImage = localImage;
//Crop image
localImage = [self getImageFromContext:localImage withImageView:selectedImage];
//Update imageView with croppedImage
[self populateImageView:localImage];
//Dismiss image picker
[imagePickerController dismissViewControllerAnimated:YES completion:nil];
}
//Crop image method
-(UIImage *)getImageFromContext:(UIImage *)image withImageView:(UIImageView *)imageView{
UIGraphicsBeginImageContext(imageView.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextRotateCTM(context, 2*M_PI);
[imageView.layer renderInContext:context];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
image = nil;
context = nil;
}
-(void)populateImageView:(UIImage *)image{
selectedImage.image = image;
}
- (void)setImage:(UIImage *)image{
imageFile = image;
}
-(UIImage *)returnImage{
return imageFile;
}
So are there any other benefits other than readability and neatness of code? Is there anyway to make this more efficient?

You have a great benchmark made by Big Nerd Ranch on that topic.
Usually I use properties as a best practice. This is useful because you have:
An expected place where your property will be accessed (getter)
An expected place where your property will be set (setter)
This usually helps in debugging (you can override the setter or set a breakpoint there to check who is changing the property and when it is changing) and you can do some lazy instantiation.
Usually I do lazy instantiation with arrays or with programmatically created views. For instance:
#property(nonatomic, strong) UIView *myView;
-(UIView*) myView {
if(!_myView) {
//I usually prefer a function over macros
_myView = [[UIView alloc] initWithFrame: [self myViewFrame]];
_myView.backgroundColor = [UIColor redColor];
}
return _myView;
}
Another important factor bolded by Jacky Boy is that with properties you have a free KVO ready structure.

Related

Where is the first good moment to take a screenshot in UIViewController

I would like to make a screenshot of my view when view is loaded. I use this method:
- (UIImage *)screenshot {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0.0f);
if( [self respondsToSelector:#selector(drawViewHierarchyInRect:afterScreenUpdates:)] ) {
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
} else {
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
}
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return screenshot;
}
The screenshot method was tested and works well. I am using the method in my UIViewController in viewDidLoad. The problem is that the result is a grey image! It's mean that view is not loaded in viewDidLoad method. The same issue can be observe in viewDidAppear. So viewDidLoad and viewDidAppear are too early. I have made workaround in viewDidLoad method:
__weak MyUIViewController *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^() {
UIImage* image = [weakSelf.view screenshot]
// do sth with image...
});
How to make a screenshot without dispatach_async ?
Try This:
- (UIImage *)screenshot {
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, [UIScreen mainScreen].scale);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
UIView-JTViewToImage project also usefull.
You could also try the snapshotViewAfterScreenUpdates method of UIView:
[self.view snapshotViewAfterScreenUpdates:YES];
Try this
New API has been added since iOS 7, that should provide efficient way of getting snapshot
snapshotViewAfterScreenUpdates: renders the view into a UIView with unmodifiable content
resizableSnapshotViewFromRect:afterScreenUpdates:withCapInsets : same thing, but with resizable insets
drawViewHierarchyInRect:afterScreenUpdates:
same thing if you need all subviews to be drawn too (like labels, buttons...)
Hope it helps.

How to set photo taken with UIImagePickerController to be viewed/modified into a custom UIViewController?

I am currently using the default UIImagePickerController, and immediately after a picture is taken, the following default screen is shown:
My question is, how would I be able to use my own custom UIViewController to view the resultant image (and therefore bypass this confirmation screen ).
Please note that am not interested in using a custom overlay for the UIImagePicker with custom camera controls or images from photo gallery, but rather just to skip this screen and assume that the photo taken is what the user would have liked.
Thanks!
Try this code to maintain your resultant image in same size:
First create IBOutlet for UIImageview.
-(void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = info[UIImagePickerControllerMediaType];
[self dismissViewControllerAnimated:YES completion:nil];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
OriginalImage=info[UIImagePickerControllerOriginalImage];
image = info[UIImagePickerControllerOriginalImage];
//----------
imageview.image = image; // additional method
[self resizeImage];
//---------
if (_newMedia)
UIImageWriteToSavedPhotosAlbum(image,self,#selector(image:finishedSavingWithError:contextInfo:),nil);
}
else if ([mediaType isEqualToString:(NSString *)kUTTypeMovie])
{
// Code here to support video if enabled
}
}
//---- Resize the original image ----------------------
-(void)resizeImage
{
UIImage *resizeImage = imageview.image;
float width = 320;
float height = 320;
CGSize newSize = CGSizeMake(320,320);
UIGraphicsBeginImageContextWithOptions(newSize,NO,0.0);
CGRect rect = CGRectMake(0, 0, width, height);
float widthRatio = resizeImage.size.width / width;
float heightRatio = resizeImage.size.height / height;
float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;
width = resizeImage.size.width / divisor;
height = resizeImage.size.height / divisor;
rect.size.width = width;
rect.size.height = height;
//indent in case of width or height difference
float offset = (width - height) / 2;
if (offset > 0) {
rect.origin.y = offset;
}
else {
rect.origin.x = -offset;
}
[resizeImage drawInRect: rect];
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
imageview.image = smallImage;
imageview.contentMode = UIViewContentModeScaleAspectFit;
}
You can customize the image picker view controller using an overlay view.
Read the documentation here.
You set up a new view, set it as the camera overlay, tell the image picker to not display its own controls and display the picker.
Inside your the code of your overlay, you call takePicture on the image picker view controller to finally take the image when you are ready.
Apple has an example of this here:
https://developer.apple.com/library/ios/samplecode/PhotoPicker/Introduction/Intro.html#//apple_ref/doc/uid/DTS40010196-Intro-DontLinkElementID_2
For transforms, you can use the cameraViewTransform property to set transformations to be used when taking the image.
After taking the picture, the delegate method would be called:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
In this method, you dismiss the imagePickerController. You have access to the image, so you can play around with the image, possibly display it in a UIImageView. So the code would be something like this:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
[self dismissViewControllerAnimated:YES completion:nil];
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera)
{
//here you have access to the image
UIImage *pickedImage = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
//Create an instance of a view controller and show the UIImageView or do your stuff there. According to you business logic.
}
}

pass image with textField to another viewController

I have two view controller class on first i have a image view plus textField inside the imageView and on second view controller there is a imageView. First view controller have a done-button, on clicking done-button i want imageView with textField pass to the secondViewController imageView.
Is there any way to do it?
Please suggest me.
- (UIImage *)renderImageFromView:(UIView *)view withRect:(CGRect)frame
{
// Create a new context the size of the frame
CGSize targetImageSize = CGSizeMake(frame.size.width,frame.size.height);
// Check for retina image rendering option
if (NULL != UIGraphicsBeginImageContextWithOptions)
UIGraphicsBeginImageContextWithOptions(targetImageSize, NO, 0);
else
UIGraphicsBeginImageContext(targetImageSize);
CGContextRef context2 = UIGraphicsGetCurrentContext();
// The view to be rendered
[[view layer] renderInContext:context2];
// Get the rendered image
UIImage *original_image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return original_image;
}
Try this function for Render image
And the below one for merge them
- (UIImage *)mergeImage:(UIImage *)img
{
CGSize offScreenSize = CGSizeMake(206, 432);
if (NULL != UIGraphicsBeginImageContextWithOptions) UIGraphicsBeginImageContextWithOptions(offScreenSize, NO, 0);
else UIGraphicsBeginImageContext(offScreenSize);
CGRect rect = CGRectMake(0, 0, 206, 432);
[imgView.image drawInRect:rect];
[img drawInRect:rect];
UIImage* imagez = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return imagez;
}
You can change coordinates and height,width according to your requirement.
Example:
This method is declared in ClassB.h
- (void) setProperties:(UIImage *)myImage MyLabel:(UILabel *)myLabel;
This above is implemented in ClassB.m
- (void) setProperties:(UIImage *)myImage MyLabel:(UILabel *)myLabel
{
//assign myImage and myLabel here
}
Then in ClassA
ClassB *classB = [[ClassB alloc] init];
[classB setProperties:myImage MyLabel:myLabel];

How to resize image pixel size programmatically

i am creating app using facebook. if i am trying to upload photo to facebook means i got following message any give idea for solve that
"The provided user_generated photo for an OG action must be at least 480px in both dimensions"
I use a function like follow to get an image with any size.
Original image should big than you wanted.(ps:You can try an image little)
+ (UIImage *)thumbnailWithImageWithoutScale:(UIImage *)image size:(CGSize)wantSize
{
UIImage * targetImage;
if (nil == image) {
targetImage = nil;
}else{
CGSize size = image.size;
CGRect rect;
if (wantSize.width/wantSize.height > size.width/size.height) {
rect.size.width = wantSize.height*size.width/size.height;
rect.size.height = wantSize.height;
rect.origin.x = (wantSize.width - rect.size.width)/2;
rect.origin.y = 0;
} else{
rect.size.width = wantSize.width;
rect.size.height = wantSize.width*size.height/size.width;
rect.origin.x = 0;
rect.origin.y = (wantSize.height - rect.size.height)/2;
}
UIGraphicsBeginImageContext(wantSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
UIRectFill(CGRectMake(0, 0, wantSize.width, wantSize.height));//clear background
[image drawInRect:rect];
targetImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
return targetImage;
}
You must provide a bigger image, with at least 480px width and height.
Your image is apparently smaller than 480px wide or tall. The problem is either that the original image is too small, or you're retrieving it incorrectly. You could, theoretically resize the image to make it bigger, but that will result in pixelation that is probably undesirable.
You should show us how you're retrieving the image. For example, when I want to pick a photo from my library, I'll use the code adapted from Picking an Item from the Photo Library from the Camera Programming Topics for iOS:
UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init];
mediaUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
// To instead show the controls to allow user to trim image, set this to YES;
// If no cropping available, set this to NO.
mediaUI.allowsEditing = YES;
mediaUI.delegate = delegate;
And then, you obviously have to implement the didFinishPickingMediaWithInfo:
#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];
UIImage *originalImage, *editedImage, *imageToUse;
// Handle a still image picked from a photo album
if (CFStringCompare ((CFStringRef) mediaType, kUTTypeImage, 0) == kCFCompareEqualTo) {
editedImage = (UIImage *) [info objectForKey:UIImagePickerControllerEditedImage];
originalImage = (UIImage *) [info objectForKey:UIImagePickerControllerOriginalImage];
if (editedImage) {
imageToUse = editedImage;
} else {
imageToUse = originalImage;
}
NSLog(#"image size = %#", NSStringFromCGSize(imageToUse.size));
if (imageToUse.size.width < 480 || imageToUse.size.height < 480)
{
[[[UIAlertView alloc] initWithTitle:nil
message:#"Please select image that is at least 480 x 480"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
}
else
{
// do something with imageToUse
}
}
[picker dismissViewControllerAnimated: YES completion:nil];
}

Resizing image to fit UIImageView

I am very new to objective c and I'm just getting my bearings. I want to do something really simple but it proves to be quite a challenge:
I am trying to display an image into an UIImageView. The image I'm showing is large and I want it scaled down to fit the UIImageView. I tried setting the AspectFit View mode but the image gets displayed to the original size and is clipped by the UIImageView. My code is below:
- (void)changeImages
{
UIImage* img11 = nil;
img11 = [UIImage imageWithContentsOfFile: [[NSBundle mainBundle] pathForResource:#"dog" ofType:#"jpeg"]];
u11.contentMode = UIViewContentModeScaleAspectFit;
u11.image = img11;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self changeImages];
}
Can anyone shed some light on this please?
Thanks!
Hi I would try this...
- (void)changeImages
{
UIImage *img11 = [UIImage imageNamed#"dog.jpeg"];
u11.contentMode = UIViewContentModeScaleAspectFit;
u11.clipsToBounds = YES;
[u11 setImage:img11];
}
- (void)viewWillAppear:animated
{
[super viewWillAppear:animated];
[self changeImages];
}
This will scale the image (up or down) so that it fits inside the imageView. Having clipsToBounds isn't necessary but will stop the image from displaying outside the frame of your imageView.
HTH.
Add to your UIViewController.m:
-(UIImage *)resizeImage:(UIImage *)image imageSize:(CGSize)size
{
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0,0,size.width,size.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
// here is the scaled image which has been changed to the size specified
UIGraphicsEndImageContext();
return newImage;
}
Using:
UIImage *image = [UIImage imageNamed:#"image.png"];
CGSize size = CGSizeMake(50, 63); // set the width and height
UIImage *resizedImage = [self resizeImage:image imageSize:size];
I hope it helps.
CGSize size=CGSizeMake(79, 84);//set the width and height
UIGraphicsBeginImageContext(size);
[image drawInRect:CGRectMake(0,0,size.width,size.height)];
UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
//here is the scaled image which has been changed to the size specified
UIGraphicsEndImageContext();
This works for sure and don't forget to import QuartzCore FrameWork..
Have a Happy Coding (^_^)....
You can also set View:Mode to Aspect Fit in the Attributes Inspector in Interface Builder
I did the following and it helped
change the mode to "aspect fill" from the default value "Scale to fill"
and add a line of code as follows (I did it in a cell configuration):
cell.photo.clipsToBounds = true
I know this is old but I wanted to add a response based on the Stanford 193p 2017 lecture 11 (around 18:45) and for anyone looking in swift as this is the first search result that showed up for me.
Basically, subclass UIView and make it look like:
class U11: UIView {
var myImage: UIImage? { didSet { setNeedsDisplay() }}
override func draw(_ rect: CGRect) {
myImage?.draw(in: bounds)
}
}
Then set the image with:
func changeImage() {
if let img11 = UIImage(named: "dog.jpeg"){
u11.myImage = img11
}
}
This is super simple and the image takes up the whole space inside of the views bounds.

Resources