I need to get the value of a UIImage's image as a string.
Previously I was doing:
if(images[imageNo].image == [UIImage imageNamed:#"image1.png"])
{
But now I have a lot more conditions so I would like to use a switch, doing:
switch(images[imageNo].image)
{
case #"image1.png":
break;
}
Is there a way to achieve this? Thanks!
Mmm I am not sure what you want to accomplish here but using [UIImage imageNamed:#"image1.png"], is definitely a very bad way to do the comparison as you are creating a new UIImage object on the fly for no reason at all, furthermore you are using the == operator when you should be using isEqual since they are objects.
I believe what you want to do is convert it to a base 64 string perhaps?. If so you an use this:
NSData *imageData = UIImageJPEGRepresentation(myImage, 1.0);
NSString *encodedString = [imageData base64Encoding];
The answer provided by H2C03 is appropriate. Use a dictionary to associate the names.
However, an alternative is using associative objects. Note that there is a cost in both space and time using associative objects, but they are convenient for just this type of case (adding a category-property).
#interface UIImage (MyImageLabel)
#property (nonatomic, copy) NSString *label;
#end
#import <objc/runtime.h>
#implementation UIImage (MyImageLabel)
static char const kImageLabelKey[1];
- (NSString*)label {
return objc_getAssociatedObject(self, kImageLabelKey);
}
- (void)setLabel:(NSString *)label {
objc_setAssociatedObject(self, kImageLabelKey, label, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
#end
Now, you can have a label property on your UIImage instances, like so:
myImage.label = someLabelStringCouldEvenBeFilename;
and
if ([myImage.label isEqualToString:someString]) {
}
The typical caveats apply regarding anything in a category. Most will encourage you to use a unique prefix or postfix to differentiate your category methods from potential future Apple names.
Note, that you could add another method to the category, like this...
+ (UIImage)myImageNamed:(NSString*)name {
id result = [self imageNamed:name];
[result setLabel:name];
return result;
}
and now you automatically set the label.
Of course, you could do this as a subclass, if you will always be creating your own image, and avoid the "nastiness" associated with associative objects (though all your images need to be MyUIImages).
#interface MyUIImage : UIImage
#property (nonatomic, copy) NSString *label;
#end
#implementation MyUIImage
// Now, you override imageNamed:
+ (UIImage*)imageNamed:(NSString*)name {
UIImage *image = [super imageNamed:name];
self.label = name;
return image;
}
#end
Both of your approaches are incorrect. The first one relies on caching (which is not documented), meanwhile the second is a syntax error - the 'case' keywords expect a compile-time constant expression.
As far as I know, there's no such a method in the iOS SDK that would return an image's filename - simply because it's not a property of the image (what would it return for a programmatically created image?). You should instead try to operate on an NSDictionary, storing the UIImage objects associated with the filenames as keys, and comparing the keys using isEqualToString:.
So you should create your images only once, and store them in a dictionary:
// assuming `images` is an already created instance variable of your class
[images setObject:[UIImage imageNamed:#"ImgOne.png"] forKey:#"ImgOne.png"];
// and so on, with every image you need
// then once you have to check against a file name, use:
UIImage *img = [images objectForKey:#"FileName.png"];
if ([someImage isEqual:img]) {
// you can now be sure that the image set to the object was once named "FileName"
}
Related
I have created a default preferences plist file, and when the app is launched, I register those default values. But I allow the user to change a single setting which changes nearly all of the settings I've registered, in addition to changing each individual setting. Basically, I allow them to change a "theme" which changes almost every other stored setting. When the user does select a theme, instead of calling setObject:forKey for every single setting and manually defining what it should be for the selected theme, I am wondering if it is wise to create another plist file for each theme. I am thinking I could simply overwrite the values stored in NSUserDefaults where the keys match. And in doing so, I could also more easily detect when the app's settings are the same settings of any theme, or if they've customized a theme. I would simply detect if the value stored in NSUserDefaults equals that of the value stored in each theme plist for each key, and if any of them differ I know they have customized it and are not using a built-in theme. If I don't utilize a plist, I would have to compare each stored value against a manually defined value, therefore defining the default value for that theme in two different locations (where I set the settings when they select a theme and where I check to see if the current settings are the same settings of an available theme).
If that's an appropriate implementation, how does one overwrite existing values inNSUserDefaultsusing the values stored in a plist? If not, what would you recommend in this situation?
See, settings is a concept in your application (storing and using a UI textSettings), which is better to design with abstraction from the actual implementation (persisting in .plists, databases et cetera) in mind.
All those individual values are grouped together by a single concept, and thus can be represented by a class in your project. This class "wraps up" implementation details related to the concept. This logic becomes isolated from other parts of your program, and when you need to change it, your changes are confined to a single entity, ergo every change is less likely to break the rest of your code.
This class can be implemented like that:
/////////////
// TextSettings.h
#import <Foundation/Foundation.h>
#interface TextSettings : NSObject <NSCoding>
#property (nonatomic, strong) UIColor *mainColor;
#property (nonatomic, copy) UIFont *font;
+ (instancetype)defaultTextSettings;
#end
/////////////
// TextSettings.m
#implementation TextSettings
+ (instancetype)defaultTextSettings
{
TextSettings *textSettings = [[TextSettings alloc] init];
textSettings.font = [UIFont systemFontOfSize:14.0f];
textSettings.mainColor = [UIColor whiteColor];
return textSettings;
}
#pragma mark - NSCoding
// Read more about NSCoding on: http://nshipster.com/nscoding/
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
_font = [aDecoder decodeObjectForKey:#"_font"];
_mainColor = [aDecoder decodeObjectForKey:#"_mainColor"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.font forKey:#"_font"];
[aCoder encodeObject:self.mainColor forKey:#"_mainColor"];
}
#pragma mark - Equality
- (BOOL)isEqual:(id)object
{
if (object == nil) {
return NO;
}
if ([object isKindOfClass:[self class]] == NO) {
return NO;
}
TextSettings *otherTextSettings = object;
return [self.font isEqual:otherTextSettings.font] && [self.mainColor isEqual:otherTextSettings.mainColor];
}
// You must override -hash if you override -isEqual
- (NSUInteger)hash
{
return self.class.hash ^ self.font.hash ^ self.mainColor.hash;
}
#end
When you have such an object you can:
easily test them for equality
easily archive and unarchive (serialize and deserialize) them
Equality testing
// TextSettings *myTextSettings
if ([myTextSettings isEqual:[TextSettings defaultTextSettings]]) {
// User didn't change the textSettings...
}
else {
// User changed the textSettings!
}
Serialization/deserialization
// In a controller responsible for displaying something according to textSettings.
// textSettings (self.textSettings) is a #property in this controller.
- (void)saveCurrentTextSettings
{
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.textSettings];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"currentTextSettings"];
}
- (void)loadTextSettings
{
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:#"currentTextSettings"];
self.textSettings = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
That's pretty much it.
When you want to add new fields to TextSettings, you must (1) declare them as #properties, (2) add checks to -isEqual: and -hash implementations and (3) add unarchiving/archiving code to -encodeWithCoder and -initWithCoder.
That's too much! you may say, but I'd say no – it is hardly an overkill. Definitely better than searching and comparing individual values in NSUserDefaults.
UPD:
To use it as just plain settings:
// Called when user chooses new value
- (void)userDidChooseFont:(UIFont *)font
{
self.textSettings.font = font;
[self saveTextSettings];
}
- (void)saveTextSettings
{
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.textSettings];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"textSettings"];
}
I have a core data entity that has a structure like this:
number (integer 16),
reference (binary)
image (binary)
I have created a class for that entity.
The header of that class has these declarations for the entity property.
#property (nonatomic, retain) NSNumber * number;
#property (nonatomic, retain) NSData * reference;
#property (nonatomic, retain) NSData * image;
but in fact, these 3 properties are
number = NSInteger
reference = NSArray
image = UIImage
because I cannot store arrays and images on core data directly, I have to convert it to NSData to save but I don't care for the property being declared as NSData, because the conversion to and from NSData is something internal to the entity and should not be exposed to code outside the class.
I want these header properties to be declared like
#property (nonatomic, assign) NSInteger number;
#property (nonatomic, retain) NSArray * reference;
#property (nonatomic, retain) UIImage * image;
and I want to, for example, when I assign an array to reference that is converted to NSData internally.
I know I have to create setters and getters to do that but my problem is that the entity is already using these names. Obviously I can rename all core data entities to have a prefix like xnumber, xreference, ximage, etc., so I will have no collisions between the names/types I want to expose and those I want to hide internally.
Is there any other alternative to that? My fear is ending with a sea of references that are similarly.
What you did in your application is probably most common fail using core data. By no means you should be encouraged to use the core data classes directly as you did, do always use subclassing, categories or (best of all) use wrappers.
Since in most cases when you edit an entity in your model you wish to delete the auto generated file(s) and create new ones those files should be unmodified. This is the main reason I discourage you to use any quick fixes such as modifying the names in your model and then creating the custom setters.
Why I suggest the wrappers most is because you can build your own interface with it. You can create exactly as many methods, accessories as you need on it, you can use data protection such as having read-only parameters... So when you modify the data model there should be no difference in the application at all, when you will possibly add some extra tables for some optimisations or some internal functionality you will have no issues hiding those accessories. Other then that having an extra layer will make it very easy for you to create some caching, easy debugging since you can put a breakpoint or log to more or less any and every accessory, you can internally maintain multithreading operations...
I can understand at this point migrating your code to some other system might take a bit long but that is something you should consider. If the application is anything but almost done I suggest you do migrate it: If you create a wrapper with same properties as are already used in the application it is possible to simply change the class names where it was already used, this shouldn't take too long. If you choose to continue working as it is you will most likely encounter some much harder issues and if nothing else remember this when you will start a new application.
Edit: Wrapper explanation and example
By wrapper I mean a class instance that holds another instance and builds an interface around it. Let me show you a nice example first:
Interface:
#interface EntityWrapper : NSObject
#property NSInteger number;
#property UIImage *image;
+ (NSArray *)fetchAll;
+ (void)invalidateCache;
#end
Implementation:
#class EntityName;
static NSArray *__entityCache = nil;
#interface EntityWrapper() {
EntityName *_boundEntity;
}
#end
#implementation EntityWrapper
- (instancetype)initWithEntity:(EntityName *)entity {
if((self = [super init])) {
_boundEntity = entity;
}
return self;
}
+ (NSArray *)fetchAll {
if(__entityCache == nil) {
NSMutableArray *toReturn = [[NSMutableArray alloc] init];
NSArray *entityArray = nil; //fetch from data base
for(EntityName *entity in entityArray)
[toReturn addObject:[[EntityWrapper alloc] initWithEntity:entity]];
__entityCache = [toReturn copy];
}
return __entityCache;
}
+ (void)invalidateCache {
__entityCache = nil;
}
- (void)setNumber:(NSInteger)number {
_boundEntity.number = #(number);
}
- (NSInteger)number {
return [_boundEntity.number integerValue];
}
- (void)setImage:(UIImage *)image {
_boundEntity.image = UIImagePNGRepresentation(image);
}
- (UIImage *)image {
return [[UIImage alloc] initWithData:_boundEntity.image];
}
#end
As you can see here I am building an interface around the entity using custom setters and getters. I even create a method to fetch all objects from the data base, next step might be to fetch them with some predicate or in this case rather some custom options. I also added a most simple cache just to see the concept.
The number is now a NSInteger instead of a NSNumber which can be quite a convenience but be careful doing this as you might need to know if number is nil. For this case you could also create another property such as BOOL numberIsSet.
Pretty much the same goes for the image. You need no transformers at all, just a getter and a setter (which is pretty much the same with transformers but this approach is much more dynamic).
So creating the wrapper kind of gives you the ultimate power. The idea is to create as small interface as possible and as simple as possible. That means there are just as many methods in the header file as needed, rest is hidden. The logic behind these methods can be extremely complicated but will still be maintainable since it is a closed system (does not depend on nothing but the entity), to give you an example:
Interface:
#property (readonly) NSDecimalNumber *heavyValue;
Implementation:
- (NSDecimalNumber *)heavyValue {
NSDecimalNumber *valueA = _boundEntity.valueA;
NSDecimalNumber *valueB = _boundEntity.valueB;
NSDecimalNumber *valueC = _boundEntity.valueC;
return [[valueA decimalNumberByAdding:valueB] decimalNumberByDividingBy:valueC];
}
Now this is quite a standard procedure and will work great but this method can be quite heavy on the CPU. If this method is called a lot you might get to a point where you want to optimise by storing the result into the entity itself. So all you do is add another value into the model heavyValue and the code:
- (NSDecimalNumber *)heavyValue {
NSDecimalNumber *toReturn = _boundEntity.heavyValue;
if(toReturn == nil) {
NSDecimalNumber *valueA = _boundEntity.valueA;
NSDecimalNumber *valueB = _boundEntity.valueB;
NSDecimalNumber *valueC = _boundEntity.valueC;
toReturn = [[valueA decimalNumberByAdding:valueB] decimalNumberByDividingBy:valueC];
_boundEntity.heavyValue = toReturn;
}
return toReturn;
}
- (void)setValueA:(NSDecimalNumber *)valueA {
_boundEntity.valueA = valueA;
_boundEntity.heavyValue = nil; //this invalidates the value
}
So that is quite an extreme change in logic behind a simple getter but the rest of your code is unharmed, it still all works as it should.
OK I have a specific situation. I am using a custom class to create some buttons and I can set their tag property with unique numbers like:
button.tag =[NSNumber numberWithInt:[10]];
This is very useful in another part of my program because I can access this unique tag like:
UIButton *clicked= (UIButton *) sender;
ButtonTag = [NSString stringWithFormat:#"%d", clicked.tag];
Now I want to pass one more unique property just like this. I am making this up but this is how I envision it
button.tagCREATED_BY_ME =[NSNumber numberWithInt:[9000]];
The question might be poorly worded but I don't know any better so I called it "tag".(correct wording might be element/property etc) How do I create a similar property to function just like .tag?
Thanks a lot!
arda
What do you want to achieve?
There is the possibility of adding an associative references. The good part about this, is that you don't need to sub-class it. So, start by creating a Category for the UIButton:
#interface UIButton (ExtraTag)
#property (nonatomic, retain) id extraTag;
#end
And the .m:
static char const * const ExtraTagKey = "ExtraTag";
#implementation UIButton (ExtraTag)
#dynamic extraTag;
- (id)extraTag {
return objc_getAssociatedObject(self, ExtraTagKey);
}
- (void)setExtraTag:(id)newExtraTag {
objc_setAssociatedObject(self, ExtraTagKey, newExtraTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
You can check the article I used.
CALayer allows Key-Value coding actually.
You can literally just do this (on any UI object):
[button.layer setValue:#(9000) forKey:#"tagCREATED_BY_ME"];
and to read it just use
[button.layer valueForKey:#"tagCREATED_BY_ME"]
Obligatory, the above is all you need to get this up and going, you're good to go.
For others, more advanced /or/ specific stuff follows:
If you need these keys to have a default value when nothing has yet been assigned to them... You can set these custom "tags" (eh) to have default return values if you name them according to a pattern. For example I start all of my layer keys name's with "customKey_". So the above would have been #"customKey_tagCREATED_BY_ME", then you can have your .m file return the default key values for any standard key like masksToBounds but then return a very specific value for your keys (aka keys that start with "customKey_") with the following method:
+(id)defaultValueForKey:(NSString *)key {
if ([key hasPrefix:#"customKey_"]) {
return #(0);
}
return [CALayer defaultValueForKey:key];
}
The reason you have to have a naming pattern (like always having the prefix "customKey_") is so you don't interfere with a CALayer's natural properties like .size and .backgroundColor, etc. Your default value you want returned will only be returned on properties (key) starting with "customKey_" or whatever naming pattern you use.
In your subclassed/custom button, you can add a string property or even an integer property whichever you feel good.
#interface CustomButton: ....
...
#property(strong) NSString *createdBy;
#end
Then you can access those as aButton.createdBy
You can also use Associated references instead of tags manipulation
#import <objc/runtime.h>
static char kThumbnailButtonAssociatedPhotoKey;
// ...
- (void)setAssociatedPhoto:(Photo *)associatedPhoto
forThumbnailButton:(UIButton *)thumbnailButton
{
objc_setAssociatedObject(thumbnailButton,
&kThumbnailButtonAssociatedPhotoKey,
associatedPhoto,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (Photo *)associatedPhotoForThumbnailButton:(UIButton *)thumbnailButton
{
return objc_getAssociatedObject(thumbnailButton,
&kThumbnailButtonAssociatedPhotoKey);
}
Now we can easily set/get the associated photo for a button:
- (void)configureThumbnailButtonForPhoto:(Photo *)photo
{
// ...
[self setAssociatedPhoto:photo
forThumbnailButton:thumbnailButton];
// ...
}
- (void)thumbnailButtonTapped
{
Photo *photo = [self associatedPhotoForThumbnailButton:thumbnailButton];
// ...
}
Blog post about tags and associated references
You can subclass UIButton.
In your subclass, add a new property:
#property (strong, nonatomic) NSNumber *tagCREATED_BY_ME;
You could look into KVC.
Or if you wanted to stick to the KISS principle - subclass UIButton and create a property.
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.
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)
}