Fetching reference to superview from UITextField? - objective-c

I have created three UIImageViews. I then added a UITextField to each image as a subview.
When the user clicks on the text field I want to capture which UIImageView ths text field belongs to. I am trying the following code :
-(void)textFieldDidBeginEditing : (UITextField *)textField {
textField = retainedObject;
MyPicture *capture = nil;
for (UIImageView *oneView in retainedObject.superview) {
if ([oneView isMemberOfClass:[myPicture class]])
capture = (UIImageView *)oneView;
}
However I get an error that UIView may not respond to count by enumeration. It looks like the superview of the textfield is UIView rather than UIImageView perhaps ? Can anybody help solve this ?
Thanks,
Martin

A UIView's superView is assumed to be a UIView. However, you can still cast it as a UIImageView, and call UIImageView methods on it, but just make sure it will always be a UIImageView without exception, as otherwise it will crash.
Source: My own applications ;)

Related

Changing image in different view

I am attempting to change the character image in the game that I am creating but I am having some issues. I have a view controller where I will have all of the characters as their own buttons, and by selecting a button it should change the character image in the GameViewController
change.h
- (IBAction)charOne:(id)sender;
change.m
- (IBAction)charOne:(id)sender
{
GameViewController *changeView = [GameViewController game];
UIImageView *Romo = [GameView changeView];
[ChangeView setImage:[UIImage imageNamed:#"testOne.png"]];
NSLog(#"Test");
}
GameViewController.m
{
IBOutlet UIImageView *changeView;
}
#property (strong, nonatomic) IBOutlet UIImageView *changeView;
This code isn't working for me, I do not receive an error message but nothing is changed after the image is selected.
On the GameViewController the UIImage name that I am attempting to change the image for is named Romo.
Any help will be appreciated
try :
[Romo setImage:[UIImage imageNamed:#"testOne.png"]];
instead of :
[ChangeView setImage:[UIImage imageNamed:#"testOne.png"]];
You're calling the setImage method on a class rather than an instance of a class. Since Romo is the instance of UIImageView you want to affect (which is a reference pointer to the UIImageView on your game view controller), that should be the instance you affect.
Also, bad practice to name instances starting with a capital letter -- they turn out looking like classes.

Change Label With Tag Only

I am creating an application with multiple buttons and corresponding labels.
The layout is in a nib (.xib) file which is connected to the class I have the code below in. I'm trying to avoid using an IBOutlet for every label, since this would create a lot of extra code.
I know there is a way to reference a label using the tag:
UILabel *countLabel = (UILabel *)[self.view viewWithTag:numOfTag];
I called this within my buttonPressed method. However, when I try to change the text
[countLabel setText:#"newLabel"];
the app crashes. Am I accessing it wrong? I'm new to XCode..Help!
Thanks :)
This is not the correct way of doing it. Firstly whenever you creating UILabel in your XIB file, you can name them there only so technically, there is no need for you to set the label values in the connected view controller. Secondly, even if you want to reset the labels at the later stage, connecting them using IBOutlets is the best bet. Scanning through all sub views and then finding a particular subview with its tag is more tedious and should be avoided in this case.
EDIT:
For your case where you need to create more than 50 buttons and labels, I would suggest you to create a custom UIView with UIButton and UILabel in it. And then in the view where you want to display them, create objects in a for loop and display them. And when a UIButton is tapped it will be easy for you to fetch the associated UILabel though the custom UIView object.
Your label must not be found with viewWithTag:, so it will be nil. And when you try to access property of nil control, it might give you a crash.
Check if your label is not nil and check if it is label using
if(countLabel != nil && [countLabel isKindOfClass:[UILabel class]])
[countLabel setText:#"newLabel"];
else
NSLog(#"countLabel is not found");
viewWithTag: will search the view in the receiver’s hierarchy whose tag property matches the value in the tag parameter. This will return first control it will encounter with tag in hierarchy. So make sure your tag needs to so unique in entire view. Just make sure you are giving immediate parent of Label instead of self.view.
Edit:
To can try this way also if you are not able to track issue.
for (UIView *child in self.view.subviews) {
if([child isKindOfClass:[UILabel class]] && [child tag] == numOfTag)
{
[child setText:#"newLabel"];
break;
}
}

Set All UILabels Hidden

Is there a way to set all UILabels as hidden in Objective-C? I'm showing and hiding labels based on if statements and feel like I'm writing really bulky code. Is there a way to select all UILabels to setHidden:YES a la CSS?
Edit: I need one of them visible at a time, not all hidden at once.
Thanks!
If all your labels lay at the same view you can use it's subviews property:
for (UIView *subview in self.view.subviews) {
if ([subview isKindOfClass:[UILabel class]]) {
subview.hidden = YES;
}
}
And if there are numerous of views with labels you can even add a category to the whole UIView.
#interface UIView (HideLabels)
- (void)hideAllLabels:(BOOL)hide withExcludedLabel:(UILabel *)label;
#end
#implementation UIView (HideLabels)
- (void)hideAllLabels:(BOOL)hide withExcludedLabel:(UILabel *)label
{
for (UIView *subview in self.view.subviews) {
if (subview != label && [subview isKindOfClass:[UILabel class]]) {
subview.hidden = YES;
}
}
}
#end
There's no other way to do this.
Edit: the code above updated according to your needs.
If you only need 1 UILabel at all time, you can reuse the same UILabel. The advantage is you use a bit less memory and you don't need to manage all the UILabels. The disadvantage is that you need to recalculate/store the coordinates to put the UILabel and stores the content of the UILabel (the management is shifted to this).
Now that the requirement has changed, the below answer is no longer valid. However, I still keep it there, in case anyone wants to hide/show all labels.
I don't think you can do it like CSS, but we can use a trick to avoid having to loop through all the UILabels to setHidden.
You can put all the UILabels as subview of a transparent UIView. The size and origin of the transparent UIView should be configured so that the coordinate is the same as when you don't use the transparent view (to avoid confusion). When you want to hide all UILabels, you can just hide the whole transparent UIView.
This has a drawback is that all the UILabels must be on top or under the existing view. This means that you cannot freely adjust some label to be on top of certain element, and some label to be below certain element on the existing view. You need to create another view for that purpose, and things will get quite messy there.

What could I add to this code to make it not remove the UIToolbar?

NSArray *subviewsList = [[NSArray alloc] initWithArray:[self.view subviews]];
for (UIView *aView in subviewsList) {
NSLog(#"%#",subviewsList);
if (![aView isEqual:sender]) {
[aView removeFromSuperview];
}
}
[subviewsList release];
I have it not remove the UIButton that you click to actually call this code, however, I haven't figured out how to get it not to remove the UIToolbar that I added to the screen via IB. Any suggestions?
EDIT: I should have been more clear, I'm sorry. The code was done to remove the ton of UIImageViews from the screen. I didn't want it to remove the uibutton that calls the method, or the toolbar.
EDIT:
This works. :)
if (![aView isEqual:sender] && ![aView isKindOfClass:[UIToolbar class]]) {
If ([aView isKindOfClass:[UIToolBar class]]) {
// the view is a uitoolbar
} else {
[aView removeFromSuperView];
}
Send from iphone, maybe syntax errors :) but this let you check if your subview is from a specific class
Hope this helps
Any number of things could be happening. Is your UIToolbar a subview or sublayer of one of the aView's you are removing?
Without knowing what all else is happening in your views (in code or in IB), it's hard to say, but also make sure that if you're adding any views or layers that they're not covering anything up. (Even if something like a UIButton is visible, it may not respond if covered by another view.)

Two UIViews in one .xib file?

i made a second uiview in mei .xib file. the first view is landscape and i get it by following code
ItemController *newItem;
newItem = [[ItemController alloc] init];
newItem.view.....
how can i "activate" the second view, so i can use it with
newItem.view2...
is that possible? the second view is portait mode, so it should be hidden and when turning the ipad the first view should be hidden and the second gets visible.
thanks
If I understand your question correctly, you can use the method willRotateToInterfaceOrientation:duration: in UIViewController.
You can declare two UIView variables and set connections to them using IB:
IBOutlet UIView *view1;
IBOutlet UIView *view2;
Then, in willRotateToInterfaceOrientation:duration: you can swap the views. Assuming that your ItemController is a subclass of UIViewController, you could have something like this:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
[self setView:view1];
}
else {
[self setView:view2];
}
}
When the user rotates the iPad this method will get called automatically.
NOTE: make sure you set shouldAutorotateToInterfaceOrientation: to return YES, and you may have to check the orientation to set the view property to the correct view initially.
EDIT: My answer is assuming that you have two views with distinct layouts/elements and not two views that are essentially the same thing sized for different orientations. If the latter is the case, there is probably a better way to do it using only one view.
The approach you are taking will lead you to a trouble situation when you have some IBActions to associate with click of buttons or change the label text (which is on xib) etc.
The best approach is to change the frame height width and positions when the orientation changes. Although this is difficult in beginning but it will save you from lots of troubles.
For assistance check Rotate UIViewController to counteract changes in UIInterfaceOrientation
Hope this helps.
Thanks,
Madhup