How to get name or identifier for a UIView component - objective-c

In the below code I want to have any identifier to the -firstView- as shown below in the code.
I attempted the following:
//NSLog(#"_[uiviews[0] _description] = %#" , [uiviews[0] _description]);
//NSLog(#"[uiviews[0] nameLabel] = %#" , [uiviews[0] nameLabel]);
//NSLog(#"[uiviews[0] textLabel]= %#" , [[uiviews[0] textLabel].text);
NSString *r = [uiviews[0] textLabel].text;
NSLog(#"[uiviews[0] textLabel]= %#", r);a
But, on activating any of them, the App crashes. Would you please let me know how to have access to the name or any string identifies that UIView.
code
UIView *firstView = uiviews[0];

Use UIView.tag to identify views in your app:
UIView* anotherView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
anotherView.tag = 100;
[view addSubview:anotherView];
UIView* anotherViewAgain = [view viewWithTag:100];
NSLog(#"anotherView and anotherViewAgain are %#the same objects", anotherView == anotherViewAgain ? #"" : #"not "); // prints "anotherView and anotherViewAgain are the same objects"

you can give a try with accessibilityIdentifier of UIView.
uiview tag, is not the best idea (or extend it with enum Int raw value).
with accessibilityIdentifier you can do a lot more logic in nice way.

Related

NSMutableArray objects being lost

I hope this makes sense...I have an NSMutableArray that I'm attempting to store multiple UIScrollView's in. Each UIScrollView is going to have multiple images and the ultimate goal is to be able to allow the user to swipe vertically for categories (each instance of UIScrollView) and horizontally for each image in that category (each instance of UIImageView). For now, until I get this code to work, I'm just creating 1 UIScrollView with 1 image and I'm adding that to scrollViewManager. This seems to add everything correctly, but when I leave this function, game over. My Array is empty. I don't understand. Am I supposed to do some sort of deep copy when I add to the Array so it doesn't get destroyed. Perhaps I'll figure it out when I wake up tomorrow, but for now, I'd like to break everything in sight. Thanks, in advance!
EDIT: Sorry for lack of details, I posted this rather late. My project is using ARC, so I'm not releasing scrollView anywhere. Here is the declaration for scrollViewManager in my header file:
#property (nonatomic, retain) NSMutableArray *scrollViewManager;
Here is the code I use to retrieve my scrollView:
UIScrollView *test = (UIScrollView*) [self.scrollViewManager objectAtIndex: 0];
And here is the code to initialize the scrollView and array:
scrollViewManager = [[NSMutableArray alloc] initWithCapacity: 1];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[scrollView setBackgroundColor:[UIColor blackColor]];
[scrollView setCanCancelContentTouches:NO];
scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = YES;
NSString *imageName = #"pic1.png";//[NSString stringWithFormat:#"pic%d.jpg", i+1];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = 400;
rect.size.width = 300;
imageView.frame = rect;
imageView.tag = 1; // tag our images for later use when we place them in serial fashion
[scrollView addSubview:imageView];
[self.scrollViewManager addObject: scrollView];
There are some things that are kind of vague. For example:
Are you using ARC, if not and you are releasing your scrollView anywhere?
Are you using the auto-create-synthesize thing?
What type of property is your scrollViewManager (weak, strong, etc).
If you are creating your ivars automatically when defining a property, your ivar should be called _scrollViewManager instead of scrollViewManager.
The use of self.scrollViewManager is correct when using this method.
I always do this kind of stuff the other way around. When I have a property like this:
#property (nonatomic, strong) NSMutableArray* myArray;
I always initialize them using the self keyword:
self.myArray = [NSMutableArray new];
And when modifying it, I always use the generated ivar:
[_myArray addObject:myFineObject];
I think this is something I kept using when moving from non-ARC to ARC. Not sure if it still the way to go, but it works like expected.

Identify UIImages Individually

I've got an app where multiple UIImages can be added to the view. Those images can then be dragged around the screen. How can I check which image has been dragged and then save that image's coordinates to a file and no other UIImage in the same view. I need a way of tagging each UIImage if possible to separate them out and identify them each individually. Hopefully this makes sense!
This is how I'm adding each UIImage to the view:
CGRect imageFrame = CGRectMake(activeView.center.x - 50, activeView.center.y - 50, 200, 200);
imageResizableView = [[SPUserResizableView alloc] initWithFrame:imageFrame];
UIImage *image = [UIImage imageNamed:#"galaxy.jpg"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageResizableView.contentView = imageView;
imageResizableView.delegate = self;
[activeView addSubview:imageResizableView];
You can use the tag property on UIVIew.
As per mentioned in the official doc:
tag An integer that you can use to identify view objects in your application.
#property(nonatomic) NSInteger tag Discussion The default value is 0. You can set the value of this tag and use that value to identify the view later.
UIImageViews are UIView subclasses, so have a tag property. Set that for each image, then when you want that one image [self.subViews viewWithTag:number]; to find it.
EDIT: If I understand this, there are many UIImageViews, but multiple imageViews may show the same image.
Assuming that, then you partition the tag's 32 bits to say 16 bits upper as the unique imageView number, and the lower 16 are the image number. You will then need to iterate through all subviews looking for the image. You can use macros to make this easier:
#define TAG_NUMBER(imageViewNum, imageNum) ((imageViewNum << 16) | imageNum)
#define IMAGE_FROM_TAG(tag) (tag & 0xFFFF)
etc
when you want to find all imageviews showing that image:
for(UIVIew *view in self.subviews) {
if(![view isKindOf:[UIIMageView class]]) continue;
int imageNum = IMAGE_FROM(view.tag);
if(imageNum == theOneIwant) {
save frame of "view"
}
}
If integer tags are good enough, then use the tag property which already exists for UIViews.
However, if you want something more, you can use obj_setAssociatedObject to add a tagName property to UIView.
#interface UIView (tagName)
#property (nonatomic, copy) NSString *tagName;
#end
--
#import <objc/runtime.h>
#implementation UIView (tagName)
static char tagNameKey[1];
- (NSString*)tagName {
return objc_getAssociatedObject(self, tagNameKey);
}
- (void)setTagName:(NSString *)tagName {
objc_setAssociatedObject(self, tagNameKey, tagName, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
#end
which can then be used like so...
NSString *imageName = #"galaxy.jpg";
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.tagName = imageName;
and later...
NSString *imageName = imageView.tagName;
EDIT
Of course, you can add whatever you want, for example to mimic viewWithTag
- (UIView*)viewWithTagName:(NSString *)tagName {
if ([self.tagName isEqualToString:tagName]) {
return self;
}
UIView *result = nil;
for (UIView *view in self.subviews) {
if ((result = [view viewWithTagName:tagName]) != nil) {
return result;
}
}
return nil;
}

array crashing at index which is in bounds?

Can anyone help me out with explaining why my array is crashing.
Basically I have two buttons which change the image in the imageView.
h:
#interface CaseStudySecondPageViewController : UIViewController
{
//scroller and back and forward buttons for custom control.
__weak IBOutlet UIScrollView *scroller;
__weak IBOutlet UIButton *back;
__weak IBOutlet UIButton *forward;
//app delegate to return the selected case study from the other controller.
AppDelegate *del;
//variables for displaying the case studies
NSArray *myImageArray;
NSInteger localSelctorInt;
}
//setup a IBOutlet to allow the image to be changed.
#property (weak, nonatomic) IBOutlet UIImageView *logoImage;
#end
m:
update method:
-(void)Updater
{
[logoImage setImage:[myImageArray objectAtIndex:localSelctorInt]];
}
previous and next buttons:
//returns to previous image if back button is clicked.
-(void) back:(id)sender
{
if (localSelctorInt > 0)
{
localSelctorInt--;
}
else
{
localSelctorInt = 0;
}
[self Updater];
}
//returns to next image if forward button is clicked. increase 7 if array size changes.
//1 removed from int as in starts at 1 and array starts at 0.
-(void) forward:(id)sender
{
if (localSelctorInt < 7)
{
localSelctorInt++;
}
else
{
localSelctorInt = 7;
}
[self Updater];
}
and finally my image array is declared in:
- (void)viewDidLoad
{
[super viewDidLoad];
//setup the delegate to allow access to the int which was modified on the page before.
del = [[UIApplication sharedApplication] delegate];
//assign a local variable to the int from the previous page.
localSelctorInt = *(del.selectorInt);
//create back and forward buttons as UIButtons first.
[back addTarget:self action:#selector(back: ) forControlEvents:UIControlEventTouchUpInside];
[forward addTarget:self action:#selector(forward:) forControlEvents:UIControlEventTouchUpInside];
//pass the ui buttons into ui bar items.
UIBarButtonItem *UIBack = [[UIBarButtonItem alloc] initWithCustomView:back];
UIBarButtonItem *UIForward = [[UIBarButtonItem alloc] initWithCustomView:forward];
//add these to an array (notice item"s").
self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:UIForward, UIBack, nil];
//initialize the array with all of the images for the case studies logos.
myImageArray = [NSArray arrayWithObjects:
[UIImage imageNamed:#"Logo_Arm.png"],
[UIImage imageNamed:#"Logo_Fife"],
[UIImage imageNamed:#"Logo_Findel.png"],
[UIImage imageNamed:#"Logo_BirkBeck.png"],
[UIImage imageNamed:#"Logo_NHS_Dudley.png"],
[UIImage imageNamed:#"Logo_NHS_Kensignton.png"],
[UIImage imageNamed:#"Logo_Yorkshire_Water.png"],
[UIImage imageNamed:#"Logo_Uni_Hertfordshire.png"],
nil];
//call update method once to load the first image selected from the previous page.
[self Updater];
}
now my app crashes when it trys to index the 4th image (3rd in the array):
* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayI objectAtIndex:]: index 3 beyond bounds [0 ..
2]'
It's probably something really simple, but id appreciate your help, cheers.
If you look at your exception, it says that your array contains 3 objects only ( ... bounds [0..2] ... ). So, my guess is that your fourth image doesn't exist ... Check spelling of [UIImage imageNamed:#"Logo_BirkBeck.png"]. Does this image really exist? It returns nil, list of objects is nil terminated, so, your array does contain 3 images only instead of 8 images.
Side Note: Don't use magic constants like localSelctorInt < 7. Always rely on real number of elements in array (_myImageArray.count). It's a way to hell ...
2nd Side Note: Don't declare ivars without underscore prefix. Do use something like this _myImageArray for ivar name.
I guess its due to not allocating the array
myImageArray = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:#"Logo_Arm.png"],
[UIImage imageNamed:#"Logo_Fife.png"],
[UIImage imageNamed:#"Logo_Findel.png"],
[UIImage imageNamed:#"Logo_BirkBeck.png"],
[UIImage imageNamed:#"Logo_NHS_Dudley.png"],
[UIImage imageNamed:#"Logo_NHS_Kensignton.png"],
[UIImage imageNamed:#"Logo_Yorkshire_Water.png"],
[UIImage imageNamed:#"Logo_Uni_Hertfordshire.png"],
nil];

iOS (Re)Use a NIB as a Template

I have created a nib file with different views. I was planning to use this nib file as a template, much like in web (i.e. html). So create a new instance of this nib fill it with actual data, create another new instance of nib & fill with actual data etc...
But when I try to do this, nib instance is not behaving the same. Only one gets created. Am I missing something? Aren't nib files supposed to be used this way?
Here's how I tried to use my nib file -
int yCoord = 0;
for(int i=0; i<[resultSet count]; i++)
{
[[NSBundle mainBundle] loadNibNamed:#"msgView" owner:self options:nil];
UIView *tmpMsgView = [[UIView alloc] initWithFrame:CGRectMake(0, yCoord, msgView.view.frame.size.width, msgView.view.frame.size.height)];
tmpMsgView = msgView.view;
UILabel *senderLabel = (UILabel *)[tmpMsgView viewWithTag:1];
[senderLabel setText:#"trial"];
[self.view addSubview:tmpMsgView];
[tmpMsgView release];
yCoord += msg.view.frame.size.height;
}
this msgView is hooked up to the nib file (through IB) and the owner of that nib file too is defined as this viewController class.
Your code is adding the same instance over and over again, not a new instance each time.
UIView *testView = [[UIView alloc] init];
testView.backgroundColor = [UIColor blueColor];
for (int i=0; i<5; i++) {
testView.frame = CGRectMake(0.0, (i+1)*40.0, 200.0, 20.0);
[self.window addSubview:testView];
}
[testView release];
and
for (int i=0; i<5; i++) {
UIView *testView = [[UIView alloc] init];
testView.backgroundColor = [UIColor blueColor];
testView.frame = CGRectMake(0.0, (i+1)*40.0, 200.0, 20.0);
[self.window addSubview:testView];
[testView release];
}
are two very different things.
the first actually makes very little sense and results in a single blue bar,
the second makes much more sense and results in 5 blue bars -- I think this is what you want.
look at the following, it will create 5 rectangles with all different colors -- this is to illustrate that each is rectangle is its seperate instance loaded from a nib:
for (int i=0; i<5; i++) {
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:#"aView" owner:self options:nil];
UIView *nibView = [nibObjects objectAtIndex:0];
nibView.backgroundColor = [UIColor colorWithRed:(i+1)*0.14 green:(i+1)*0.11 blue:200.0 alpha:1.0];
nibView.frame = CGRectMake(0.0, (i+1)*40.0, 200.0, 20.0);
[self.window addSubview:nibView];
}
now, if we assign our nibObjects array only once before the loop, we again have the same issue in that we add the same instance over and over again, which will result in one rectangle only:
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:#"aView" owner:self options:nil];
for (int i=0; i<5; i++) {
UIView *nibView = [nibObjects objectAtIndex:0];
nibView.backgroundColor = [UIColor colorWithRed:(i+1)*0.14 green:(i+1)*0.11 blue:200.0 alpha:1.0];
nibView.frame = CGRectMake(0.0, (i+1)*40.0, 200.0, 20.0);
[self.window addSubview:nibView];
}
hope this helps
You have memory management issues in your code.
UIView *tmpMsgView = [[UIView alloc] initWithFrame:CGRectMake(0, yCoord, msgView.view.frame.size.width, msgView.view.frame.size.height)];
You alloc/init a UIView and on the next line you store some other view in the variable. You lose the pointer to the UIView and therefore you leak its memory.
Whether the code using senderLabel will work depends on what you defined in the nib file.
In [tmpMsgView release]; you're most probably releasing something you do not own (the pointer no longer points to the UIView you alloc/inited). The issue here depends on how you declare msgView. If you are releasing an object you do not own, it might get deallocated and that might be the reason you do not see it in your app.
What you are trying to do is fine - this is what is routinely done for loading table view cells, for example.
If I do this I have a single outlet from the view controller (which is set as files owner which you have done). This will be the topmost object in the nib, eg a UIView. All of your other Nib components are just subviews of this, you can identify with tags or, if your topmost view is a custom view, that can have outlets which are connected appropriately.
When you do loadNibNamed this will set your outlet ivar to the topmost object. You then assign this to a method level variable, and set your ivar back to nil. You can then do what you like with this before adding it as a subview to something else. Next time you load the nib, you get another fresh version.
Hope that makes sense, let me know if I can add anything else. The problem in your code is that you are doing things with msgView.view instead of the top level object.

UIImageView.hidden = NO; but image is not visible?

SomeImage is UIImageView* globally declared
-(void)InMethodCalledFromViewDidLoad
{
SomeImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"SomeImage.png"]];
SomeImage.frame = CGRectMake(0, 640, 1024,110);
[self.view addSubview:SomeImage];
SomeImage.hidden = YES;
[self OneMoreMethod];
}
-(void)OneMoreMethod{
SomeImage.hidden = NO;//image becomes visible
[self SecondMethod];
/*but now from this point onwards even if SomeImage.hidden changed to NO then only nummerical value of SomeImage.hidden changes but image itself stays hidden doesnt become visible at all */
}
-(void)SecondMethod
{
int tmp = 0;
NSArray* PosAndSizeArrForCurrSlot = [[PosAndSizeArr objectAtIndex:SlotId] componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" "]];
for(NSString* values in PosAndSizeArrForCurrSlot)
PositionAndSize[tmp++] = [values intValue];
}
i am not able to understand why SomeImage is not being visible even after setting hiiden property to NO after SecondMethod is called.
What kind of device are you trying to display the image on?
SomeImage.frame = CGRectMake(0, 640, 1024,110);
Will most likely try to display the imageview outside of the visible area of your device.
Also you should really consult this guide: http://google-styleguide.googlecode.com/svn/trunk/objcguide.xml
Only constants and classes should start with a capital letter, variable and method names should always start with a lowercase letter.
This might be a "duh" answer, but seems to always bite me in the butt, is your imageview connected to your .xib? If the outlet isn't set, it won't receive the changes.
Can you put some NSLog on the front and end, so that you can make sure the code will execute to the point you make the image visible?
-(void)OneMoreMethod{
//SomeImage.hidden = NO;//image becomes visible
NSLog(#"before SecondMethod");
[self SecondMethod];
NSLog(#"after SecondMethod");
SomeImage.hidden = NO;//image becomes visible
NSLog(#"after hidden = No");
}
What I am guess is that there is some crash in the [self SecondMethod] , then never arrive SomeImage.hidden = NO;