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)
}
object-C style
#interface TestViewController:UIViewController{
NSArray *dataList;
}
#end
#implementation TestViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSDictionary *dict1 =[[NSDictionary alloc] initWithObjectsAndKeys:#"32",#"age",#"andy",#"name", nil];
NSDictionary *dict1 =[[NSDictionary alloc] initWithObjectsAndKeys:#"34",#"age",#"smith",#"name", nil];
NSDictionary *dict1 =[[NSDictionary alloc] initWithObjectsAndKeys:#"27",#"age",#"jonathan",#"name", nil];
dataList = [[NSArray alloc]initWithObjects:dict1,dict2,dict3,nil];
}
#end
I want to make same code in Swift
so I typed swift style as follows
class ViewController: UIViewController {
var datalist = [Dictionary]() //Compile Error -> "Missing argument for parameter #1 in call"
// I can't understand error. What does it mean?
override func viewDidLoad() {
super.viewDidLoad()
let dict1 = ["age":"32","name":"andy"]
let dict2 = ["age":"34","name":"smith"]
let dict3 = ["age":"27","name":"jonathan"]
datalist = [dict1,dict2,dict3] //Compile Error -> 'ViewController' does not have a member named 'datalist'
}
}
but 2 Error
I don't know why issue error
Can you help me?
Arrays in swift do not take a parameter, you just create one by setting the array equal to [] (with or without values), for example:
var array : [Int] = []
var array2 = [1,2,3]
would create an array of integers.
Also, Dictionaries in swift need to know the types of the key and value, for example:
Dictionary<String, String>
But there is also a shorthand for creating dictionaries that looks like:
[String:String]
(Assuming String is the type for your key and value).
So for your example, you could rewrite your datalist object to be declared as:
var datalist : [[String:String]] = []
Then you can use the datalist object in the way you are using it, or by appending [String:String] objects to it.
The EKCalendarItem has the property "Location", but it is a NSString.
New iOS8 functionality shows a nice map for an event, so there must be a CLLocationCoordinate2D attached to the EKCalendarItem, correct?
Where can I find this CLLocationCoordinate2D?
this should get what you need:
for (EKEvent *calEvent in self.allMyEvents) {
EKStructuredLocation *location = (EKStructuredLocation *)[calEvent valueForKey:#"structuredLocation"];
if (location) {
}
}
EKCalendarItem does not contain any CLLocationCoordinate2D property it has location which is NSString as you mentioned in your question.
You can use location property to get co-ordinates. You can get the coordinates from a string using CoreLocation framework's CLGeocoder .
You can use this code.
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:locationString completionHandler:^(NSArray *placemarks, NSError *error) {
if([placemarks count]) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
NSLog(#"coordinate = (%f, %f)", coordinate.latitude, coordinate.longitude);
}
}];
Here locationString is the location string retrieved from EKCalendarItem 's location property. The default iCal app must be doing something similar, Hope this helps you.
I know this has been asked a million times, but I've been making a mess...
So basically what I'm trying to do is send an object from a details view to a favorites view with all of it's properties.
I've already got a button working to add a string [one property of the object] to favorites
button pressed code:
- (void)buttonPressed:(id) sender
{
NSMutableArray *favss = [[[NSUserDefaults standardUserDefaults] objectForKey:#"Favorite"]mutableCopy];
if(favss != nil)
{
NSLog(#"Array found. Contents: %#",favss);
}
else
{
favss = [[NSMutableArray alloc] initWithCapacity:0];
}
[favss addObject:self.word.head];
[[NSUserDefaults standardUserDefaults] setObject:favss forKey:#"Favorite"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"Number of items in my array is: %d", [favss count]);
}
my object is stored in it's own class:
#interface Words : NSObject {
NSString *head;
NSString *pro;
NSString *def;
}
#property(nonatomic, copy) NSString *head;
#property(nonatomic, copy) NSString *pro;
#property(nonatomic, copy) NSString *def;
when trying to run [favss addObject:self.word] the app obviously freaked out because objects can't be added to NSUserDefaults -- so I tried NSCoding but that turned my entire details view BLACK -- I've tried sending my three strings separately and that's fine but then they are all completely separated which kind of defeats the purpose -- and I somehow end up completely jacking up my arrays with all the different code I've been trying because now I keep getting this error:
Array found. Contents: <62706c69 73743030 d4010203 0405081d 1e542474 6f705824 6f626a65 63747358 24766572 73696f6e 59246172 63686976 6572d106 0754726f 6f748001 a6090a13 14151655 246e756c 6cd40b0c 0d0e0f10 11125468 65616456 24636c61 73735370 726f5364 65668002 80058003 8004615d f4536261 316f10cd 005b0070 00612075 2075005d 00202460 7c98003b 00208d34 002025b7 59277ea2 559c62a5 ff5e4e0a 58993002 24615207 54080020 25b77b54 662f7b54 5f978d77 ff0c5c31 60154e0d ff5e9898 30022462 63287740 002025b7 524d4e0d ff5e6751 ff0c540e 4e0dff5e 5e973002 24639644 7740003b 00208ddf 968f0020 25b7674e 5f3a83ab 5f977968 ff0cff5e 50127535 5f719662 76848001 738b5165 4e86573a 30022464 62767740 002025b7 624bff5e 95e8678b 5f805916 770b3002 24656cbf 7740003b 0020987a 77400020 25b74f60 ff5e6cb3 8fb95f80 4e0b8d70 ff0c4e0d 8fdc5c31 662f4e5d 773c6865 30022466 4eb28fd1 002025b7 4f607231 5a03513f ff0c5a03 513f5c31 ff5e4f60 30022467 72758fde 002025b7 90a35e74 5b506211 72385173 8fdb0020 201c725b 68da201d ff0c5f20 53d453d4 89c15230 62118fde 740690fd 4e0d7406 ff0c751f 6015628a 4ed6ff5e 50124e86 30022468 5df47ed3 002025b7 4f604ee5 4e3a628a 79d1957f ff5e5012 5c316709 597d5904 55e6003f 00202469 7167987e 003a0020 89c10020 201c5df4 5bb6201d 3002d217 18191c58 24636c61 73736573 5a24636c 6173736e 616d65a2 1a1b5557 6f726473 584e534f 626a6563 7455576f 72647312 000186a0 5f100f4e 534b6579 65644172 63686976 65720008 00110016 001f0028 00320035 003a003c 00430049 00520057 005e0062 00660068 006a006c 006e0071 00750212 02170220 022b022e 0234023d 02430248 00000000 00000201 00000000 0000001f 00000000 00000000 00000000 0000025a>
Basically, I just want my button to add the object that is being displayed in the details view into an array that is passed into NSUserDefaults to be displayed in a table view on the other side (which can then be selected to display the details of each object again)...and I know it's been asked a lot but...well, I can't even display my array at the moment...
If I understand you correctly, you need to store an array of objects (Word) that has 3 values (head, pro, def).
I suggest you store those three values in an NSDictionary:
head="xxx"
pro="yyy"
def="zzz"
and then you store this NSDictionary in an array, which is then stored in NSUserDefaults.
If you are adamant in storing your custom objects, you need to expand them a little.
The answer to this SO questions should get you there:
How to store custom objects in NSUserDefaults
i did it like this in the end:
- (void)apopbuttonPressed:(id) sender
{
NSMutableArray *myfavs = [[[NSUserDefaults standardUserDefaults] objectForKey:#"MyFavoritez"]mutableCopy];
if(myfavs != nil)
{
NSLog(#"Array found. Contents: %#",myfavs);
}
else
{
myfavs = [[NSMutableArray alloc] initWithCapacity:0];
}
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:#"MyFavoritez"];
if (dataRepresentingSavedArray != nil)
{
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
if (oldSavedArray != nil)
_myfavs = [[NSMutableArray alloc] initWithArray:oldSavedArray];
else
_myfavs = [[NSMutableArray alloc] init];
}
[_myfavs addObject:self.word];
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:_myfavs] forKey:#"MyFavoritez"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"Number of items in my array is: %d", [_myfavs count]);
// [self performSegueWithIdentifier:#"passFavs" sender:favs];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"passFavs"]) {
FavViewController *con = segue.destinationViewController;
con.myFavsTwo = _myfavs; }
}
and
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
myFavsTwo = [NSKeyedUnarchiver unarchiveObjectWithData:[[[NSUserDefaults standardUserDefaults] objectForKey:#"MyFavoritez"] mutableCopy]];
[self.tableView reloadData];
NSLog(#"Number of items in my array is: %d", [myFavsTwo count]);
}
in case anyone else runs into similar issues
I am trying to implement a simple drag and drop operation in a tableView. However, when I try to retrieve the data from the pasteboard using readObjectsForClasses, I get a runtime exception saying
"[__NSCFConstantString initWithBytes:length:encoding:]: unrecognized selector sent to instance "
This is my acceptDrop method where the problem occurs. Can someone please help point out what I am doing wrong.
(BOOL) tableView: (NSTableView *) view
acceptDrop: (id ) info
row: (NSInteger) row
dropOperation: (NSTableViewDropOperation) op
{
NSArray *pBoardClasses = [[NSArray alloc] initWithArray:[NSArray arrayWithObjects:[NSStringPboardType class], [NSDragPboard class], nil]];
NSPasteboard *board =[info draggingPasteboard];
if(![board canReadObjectForClasses:pBoardClasses options:nil])
{
NSLog(#"No acceptable data format in pasteboard. Cannot perform this operation!");
return NO;
}
NSArray * dFromPboard = [board readObjectsForClasses:pBoardClasses options:nil];
}
use [NSString class] instead of [NSStringPboardType class]
also: [NSDragPboard class] looks like it's not right. Remove this and test if it works with [NSString class] only.
NSArray *stringObjects = [pboard readObjectsForClasses:#[ [NSString class], [NSAttributedString class] ] options:#{}];
if(stringObjects.count > 0) {
NSString *myStr = stringObjects[0];
//…
}
//…