Unable to set UIImage, always returns nil - ios

This is probably a ridiculous question but I just can't figure it out for the life of me. I have a class which subclasses NSObject which has a property called image setup, like this:
#property (strong, nonatomic) UIImage *image;
Somewhere else I initialize the class and attempt to set the image in the class, like this:
UIImage *image = [UIImage imageNamed:#"Test"];
Class *item = [[Class alloc] init];
item.image = image;
But when I try to call item.image it is always nil.
The image called Test is in the project and is used elsewhere so I know it has access to the image, but for some reason it isn't being copied to the instance of my class. I have put NSLog messages and breakpoints directly after setting the image which have shown it to be nil as well as using commands via the debugger which have also shown the image in the class to be nil while the UIImage I create to copy is not nil.
I know I am doing something wrong but I have searched and can't figure out what it is.
Thanks for looking, any help is much appreciated.
edit:
I am trying to access the image from a method inside of the class.
- (void)save {
if (self.image != nil) {
// do some stuff
} else {
NSLog(#"image is nil");
}
}
And it is always coming up nil.
edit 2:
Thanks again everyone. I figured out what the problem was. I was overriding the setters/getters which was causing the issue.

Is it a .png file? Try doing it like this:
UIImage *image = [UIImage imageNamed:#"Test.png"];

Related

Initialize a subclass from a superclass in Objective C

I have created a UIImage subclass named MyImage.
MyImage obviously responds to every method originally implemented by UIImage. I would like to completely hide UIImage implementation, so for example MyImage redeclares a method like:
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets;
to
- (MyImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets;
I attempt to write the implementation like:
- (MyImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets {
UIImage *original = [super resizableImageWithCapInsets:capInsets];
MyImage *result = [[[self class] alloc] initWithUIImage:original];
return result;
}
- (id) initWithUIImage:(UIImage *)image {
// HOW TO IMPLEMENT THIS METHOD???
}
but I stopped at initWithUIImage method. How can I achieve such a behavior without using composition?
You don't want to do that. Its a lot of unnecessary code with a high risk of breaking something. Don't redeclare these methods. Is there a specific reason that you want to do that?
The problem here is simple and it is called: INHARITANCE.
Do not do inaritance but provide some class which owns UIImage. It will be easier and more relialeble.
Another issue is that you didn't expain why you need change something in UIImage! I'm prety sure yuo are trying to resolve some simple problem in nasty way.
The answer is that you cannot do what it seems like you're attempting to do. MyImage IS a UIImage, meaning it implicitly has all methods and properties of UIImage. You can add new ones, but never remove existing ones.
And UIImage is used all over the system APIs. What exactly are you attempting to accomplish by doing this?

Custom ImageView doesn't display image

I have created on custom imageView class. And am trying to override the image setter method. But for some reason the imageView is not displaying anything, though the image is getting assigned onto it.
The code is as follows:
#implementation CustomImageView
#synthesize image = _image;
- (void)setImage:(UIImage *)correctedImage
{
_image = correctedImage;
}
#end
I have tried removing the setter method. i.e Without overriding any method at all. Still it is not displaying anything. :(
The problem was that I had to set the image by passing it to the super.
[super setImage: correctedImage];
Simply, setting it from the base class doesn't seen to work :/

How to create a UIImage property that can be accessed from any method?

I'm trying to learn objective-c and app design for Xcode through books and example, but can't seem to understand how to create a global property for a UIImage, set an image to that property, and then access that UIImage in a different method.
In my FirstViewController.m file, I added the following lines:
#interface FirstViewController ()
#property (strong, nonatomic) UIImage *workingImage;
#end
#implementation FirstViewController
- (IBAction)myMethod1:(id)sender {
... bunch of code ...
UIImage *workingImage = [info objectForKey:UIImagePickerControllerOriginalImage];
}
- (IBAction)button press:(id)sender {
CGContextRef ctx;
CGImageRef imageRef = [self.workingImage CGImage];
...bunch of code...
}
So basically I am trying to create an image variable called workingImage that I set in my method to be an actual image, and then which gets used by CGImageRef after the user pressed the button. However I don't think I have things setup correctly, because imageRef never gets set to my image.
Can someone please show me what I'm doing wrong? (And FYI, this is a code snippet from a very simple app in which the user takes a photo and then I edit it's pixels)
Here you're assigning the image to a local variable:
UIImage *workingImage = [info objectForKey:UIImagePickerControllerOriginalImage];
when what you want is to set the image to the property:
self.workingImage = [info objectForKey:UIImagePickerControllerOriginalImage];

Adding an image to a NSObject - Possible?

I'm going to have objects, read from a .csv (Comma seperated file) which contains file names, later. Thats why i'm trying to do it like this.
What I would like to accomplish is to have the button get the image from the filename in the csv.
What i've tried so far:
The Object:
#interface question : NSObject
{
#private
UIImage *imageName;
}
#property (nonatomic, retain)UIImage *imageName;
(I have tried with NSString aswell as UIImage, neither works like I want them)
ViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
question *question1 = [[question alloc]init];
[question1.imageName initWithContentsOfFile:#"Default.png"];//Will be read from a csv later on, just typing it in manually for a test
testImage = question1.imageName;
}
-(void)imageshow
{
//(UIImage *)testImage;(NSString *)imageNameString; Didnt work
//[self.testImage initWithContentsOfFile:#"%#",questiont.imageName]; - Doesnt work either
[testButton setImage:testImage forState:UIControlStateNormal];
}
-(IBAction)test:(id)sender
{
[self imageshow];
}
Where this code fails is when I press the test button, nothing happens (not crash)
How can I do this properly?
(Add an image with a text filename to a NSObject and then show it in a button/image view)
question1.img = [UIImage imageNamed:#"Default.png"];
[testButton setImage:question1.img forState:UIControlStateNormal];
and yes you can try the following for dynamic images
question1.img = [UIImage imageNamed:[NSString stringWithFormat:"%#",imgName]];
imgName => is the name of the image not the image
example: "abc.png" or "123.png" ,etc
if your property is named imageName the accessor variable is automaticly named _imageName.
You are using two different variables in your code.
#interface question : NSObject
{
#private
UIImage *_imageName;
}
#property (nonatomic, retain)UIImage *imageName;
imageName is not a great name for an property that contains an image.. it would better fit to a string.
There are some things to change.
For mere conventional reasons write all class names with an upper case at the beginning. It eases reading, exchange in forums as SO and avoids mistakes.
Second name variables either speaking or abstract, preferrably speaking. But to not choose a mislieading name such imageName. There should be a name in that variable, not an image, or maybe the graphic that displays a name. :)
imageWithContentsOfFile expects a fully qualified file name. If "Default.png" is part of your boundle, as I guess by its name, then imageNamed:#"Default.png" would do.
Your setImage looks nearly good. It cannot work of course while your image is (null). However, it is not good business practis accessing the iVar direct at this point. You shoudl use its setter/getter. Use instead:
[self.testButton setImage:self.testImage forState:UIControlStateNormal];
In your case it does not make much of a difference. But similar to the other conventions it helps avoiding errors when ever you mix your code with some code that you found on the web or when you work in a team.

UIImageView - How to get the file name of the image assigned?

Is it possible to read the name of an UIImageView's UIImage
that's presently stored in the UIImageView?
I was hoping you could do something kind of like this, but haven't figured it out.
NSString *currentImageName = [MyIImageView getFileName];
you can use setAccessibilityIdentifier method for any subclass of UIView
UIImageView *image ;
[image setAccessibilityIdentifier:#"file name"] ;
NSString *file_name = [image accessibilityIdentifier] ;
Nope. You can't do that.
The reason is that a UIImageView instance does not store an image file. It stores a displays a UIImage instance. When you make an image from a file, you do something like this:
UIImage *picture = [UIImage imageNamed:#"myFile.png"];
Once this is done, there is no longer any reference to the filename. The UIImage instance contains the data, regardless of where it got it. Thus, the UIImageView couldn't possibly know the filename.
Also, even if you could, you would never get filename info from a view. That breaks MVC.
No no no… in general these things are possible. It'll just make you feel like a dirty person. If you absolutely must, do this:
Create a category with your own implementation of +imageNamed:(NSString*)imageName that calls through to the existing implementation and uses the technique identified here (How do I use objc_setAssociatedObject/objc_getAssociatedObject inside an object?) to permanently associate imageName with the UIImage object that is returned.
Use Method Swizzling to swap the provided implementation of imageNamed: for your implementation in the method lookup table of the Objective-C runtime.
Access the name you associated with the UIImage instance (using objc_getAssociatedObject) anytime you want it.
I can verify that this works, with the caveat that you can't get the names of UIImage's loaded in NIBs. It appears that images loaded from NIBs are not created through any standard function calls, so it's really a mystery to me.
I'm leaving the implementation up to you. Copy-pasting code that screws with the Objective-C runtime is a very bad idea, so think carefully about your project's needs and implement this only if you must.
There is no native way to do this; however, you could easily create this behavior yourself.
You can subclass UIImageView and add a new instance variable:
NSString* imageFileName;
Then you could override setImage, first setting imageFileName to the filename of the image you're setting, and then calling [super setImage:imageFileName]. Something like this:
-(void) setImage:(NSString*)fileName
{
imageFileName = fileName;
[super setImage:fileName];
}
Just because it can't be done natively doesn't mean it isn't possible :)
if ([imageForCheckMark.image isEqual:[UIImage imageNamed:#"crossCheckMark.png"]]||[imageForCheckMark.image isEqual:[UIImage imageNamed:#"checkMark.png"]])
{
}
Nope. No way to do that natively.
You're going to have to subclass UIImageView, and add an imageFileName property (which you set when you set the image).
Neither UIImageView not UIImage holds on to the filename of the image loaded.
You can either
1: (as suggested by Kenny Winker above) subclass UIImageView to have a fileName property or
2: name the image files with numbers (image1.jpg, image2.jpg etc) and tag those images with the corresponding number (tag=1 for image1.jpg, tag=2 for image2.jpg etc) or
3: Have a class level variable (eg. NSString *currentFileName) which updates whenever you update the UIImageView's image
Or you can use the restoration identifier, like this:
let myImageView = UIImageView()
myImageView.image = UIImage(named: "anyImage")
myImageView.restorationIdentifier = "anyImage" // Same name as image's name!
// Later, in UI Tests:
print(myImageView.restorationIdentifier!) // Prints "anyImage"
Basically in this solution you're using the restoration identifier to hold the image's name, so you can use it later anywhere. If you update the image, you must also update the restoration identifier, like this:
myImageView.restorationIdentifier = "newImageName"
I hope that helps you, good luck!
This code will help you out:-
- (NSString *)getFileName:(UIImageView *)imgView{
NSString *imgName = [imgView image].accessibilityIdentifier;
NSLog(#"%#",imgName);
return imgName;
}
Use this as:-
NSString *currentImageName = [self getFileName:MyIImageView];
In short:
uiImageView.image?.imageAsset?.value(forKey: "assetName")
UIImage has an imageAsset property (since iOS 8.0) that references the UIImageAsset it was created from (if any).
UIImageAsset has an assetName property that has the information you want. Unfortunately it is not public, hence the need to use value(forKey: "assetName"). Use at your own risk, as it's officially out of bounds for the App Store.
Yes you can compare with the help of data like below code
UITableViewCell *cell = (UITableViewCell*)[self.view viewWithTag:indexPath.row + 100];
UIImage *secondImage = [UIImage imageNamed:#"boxhover.png"];
NSData *imgData1 = UIImagePNGRepresentation(cell.imageView.image);
NSData *imgData2 = UIImagePNGRepresentation(secondImage);
BOOL isCompare = [imgData1 isEqual:imgData2];
if(isCompare)
{
//contain same image
cell.imageView.image = [UIImage imageNamed:#"box.png"];
}
else
{
//does not contain same image
cell.imageView.image = secondImage;
}
You can use objective c Runtime feature for associating imagename with the UImageView.
First import #import <objc/runtime.h> in your class
then implement your code as below :
NSString *filename = #"exampleImage";
UIImage *image = [UIImage imagedName:filename];
objc_setAssociatedObject(image, "imageFilename", filename, OBJC_ASSOCIATION_COPY);
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
//You can then get the image later:
NSString *filename = objc_getAssociatedObject(imageView, "imageFilename");
Hope it helps you.
Get image name Swift 4.2
There is a way if you want to compare button image names that you have in assets.
#IBOutlet weak var extraShotCheckbox: UIButton!
#IBAction func extraShotCheckBoxAction(_ sender: Any) {
extraShotCheckbox.setImage(changeCheckBoxImage(button: extraShotCheckbox), for: .normal)
}
func changeCheckBoxImage(button: UIButton) -> UIImage {
if let imageView = button.imageView, let image = imageView.image {
if image == UIImage(named: "checkboxGrayOn") {
return UIImage(named: "checkbox")!
} else {
return UIImage(named: "checkboxGrayOn")!
}
}
return UIImage()
}
Swift 3
First set the accessibilityIdentifier as imageName
myImageView.image?.accessibilityIdentifier = "add-image"
Then Use the following code.
extension UIImageView {
func getFileName() -> String? {
// First set accessibilityIdentifier of image before calling.
let imgName = self.image?.accessibilityIdentifier
return imgName
}
}
Finally, The calling way of method to identify
myImageView.getFileName()
I have deal with this problem, I have been solved it by MVC design pattern, I created Card class:
#interface Card : NSObject
#property (strong,nonatomic) UIImage* img;
#property (strong,nonatomic) NSString* url;
#end
//then in the UIViewController in the DidLoad Method to Do :
// init Cards
Card* card10= [[Card alloc]init];
card10.url=#"image.jpg";
card10.img = [UIImage imageNamed:[card10 url]];
// for Example
UIImageView * myImageView = [[UIImageView alloc]initWithImage:card10.img];
[self.view addSubview:myImageView];
//may you want to check the image name , so you can do this:
//for example
NSString * str = #"image.jpg";
if([str isEqualToString: [card10 url]]){
// your code here
}
use below
UIImageView *imageView = ((UIImageView *)(barButtonItem.customView.subviews.lastObject));
file_name = imageView.accessibilityLabel;
The code is work in swift3 - write code inside didFinishPickingMediaWithInfo delegate method:
if let referenceUrl = info[UIImagePickerControllerReferenceURL] as? NSURL {
ALAssetsLibrary().asset(for: referenceUrl as URL!, resultBlock: { asset in
let fileName = asset?.defaultRepresentation().filename()
print(fileName!)
//do whatever with your file name
}, failureBlock: nil)
}

Resources