I actually wrote a method which switches some UIViews. When I enter the method I have to know which is my current view to remove exactly this one from the superview. I declared a property for this purpose in the header file:
#property (weak, nonatomic) UIView *currentView;
After I changed to a certain view in my method, I want to assign this view to the property in order to use it when I enter the method again and remove this view from the superview if requested. The method looks like this:
...
nextView = [self loadNextView]; // the view is loaded from a NIB here
if (self)
{
[self viewWillDisappear:YES];
[[self currentView] removeFromSuperview];
[[self view] addSubview:nextView];
[self currentView] = [self nextView];
...
Unfortunately the compiler tells me that currentView is not assignable here. Is there another, hopefully better, way to remeber the curernt view for my purpose or should I use a completely different way?
Instead of the following line,
[self currentView] = [self nextView];
do as follows:
[self setCurrentView:[self nextView]];
You can't assign to the value of a function or method call (it returns an rvalue). You have to use the property accessor syntax:
self.currentView = [self nextView];
or explicitly invoke the setter:
[self setCurrentView:[self nextView]];
Try this
Replace
[self currentView] = [self nextView];
with
self.currentView = [self nextView];
Related
I have the following code to generate a UIBUtton from a method file called FirstViewController, since the location of the button will change in different secondviewController or thirdViewController, is it possible to set a variable for the location (CGRect) of the unbutton in the FirstViewController and change the CGRect Value in the second or third viewController?
In FirstViewController.m
-(void)method:(UIView *)_view {
UIButton*Touch1= [UIButton buttonWithType:UIButtonTypeRoundedRect];
[Touch1 addTarget:self action:#selector(TouchButton1:) forControlEvents:UIControlEventTouchUpInside];
[Touch1 setFrame:CGRectMake(50,50, 100, 100)];
**//I want to set a variable for the CGRectMake**
Touch1.translatesAutoresizingMaskIntoConstraints = YES;
[Touch1 setBackgroundImage:[UIImage imageNamed:#"1.png"] forState:UIControlStateNormal];
[Touch1 setExclusiveTouch:YES];
[_view addSubview:Touch1];
NSLog(#"test ");
}
In SecondViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
ViewController * ViewCon = [[ViewController alloc]init];
**//Change variable here by defining the new CGRect here.**
[ViewCon method:self.view];
}
This pattern is incorrect:
ViewController * ViewCon = [[ViewController alloc]init];
[ViewCon method:self.view];
as you are allocating a new view controller just to use one of its the method and then you are throwing the view controller instance away. It's extremely inefficient and inconvenient.
Either move the method to a utility class, as a class method:
[Utils method:self.view rect:rect];
or subclass UIViewController and implement the method in that base class and then derive all similar view controllers from that base class, passing any variables into it.
[self method:rect]; // method implemented in MyBaseViewController
You also asked this question before and accepted an answer that promotes the use of this bad pattern. That will mislead others into using this bad pattern.
I have custom UIViewController class called MSPageViewController with and associated nib file. I have an IBOutlet which is a UIImageView called pageImage.
Now, I want to use this view controller in another UIViewController which will display a series of my custom MSPageViewController in a UIPageViewController. So, I use the following code:
// alloc and init my custom view controller
MSPageViewController *page1 = [[MSPageViewController alloc] initWithNibName:#"MSPageViewController" bundle:nil];
// I must call this or, the image that I set below will always be null
// why? I guess it's because the view hasn't been drawn yet because it hasn't been displayed, so I need to force the redraw - but this is my question. Is this is the right approach?
[page1.view setNeedsDisplay];
// set the image
page1.pageImage.image = [UIImage imageNamed:#"tutorialPage1.png"];
// make my array of view controllers, it expects an array because could be double-sided
NSArray *viewController = [NSArray page1];
// pass the array that contains my custom view controller
[self.pageController setViewControllers:viewController direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
So am I doing this right? I have to force the redraw so that my outlets exist when I try to assign to them?
It's not the setNeedsDisplay part that you "need", it's the self.view part. By accessing the view property you are forcing the view controller to actually load the NIB. I guess that as a side effect of this, the pageImage property is populated as well (and was nil before you called self.view).
So, just calling self.view; instead of [self.view setNeedsDisplay]; should be enough.
As others have noted, pageImage (a UIImageView?) is likely not loaded from the nib yet when you're accessing it.
If you have a custom getter for pageImage, you could do the following:
- (UIImageView*) pageImage
{
[self view];
return _pageImage; // assuming the property backing ivar is synthesized as _pageImage.
}
But my personal preference would be to not expose the imageview itself and just expose a property for image. Then you can set the image to the viewcontroller regardless of it's loaded state, and internally set it to the imageView once the view loads:
- (void) setImage: (UIImage*) image
{
_image = image;
if ( self.isViewLoaded )
{
self.pageImage.image = image;
}
}
- (void) viewDidLoad
{
[super viewDidLoad];
self.pageImage.image = self.image;
}
If you moved some code to the viewDidLoad method you would be guaranteed that the view had been drawn.
Firstly, I've already tried to search for solutions online but none works for me and I'm thinking since I'm using ECSlidingViewController to navigate around the app, I can't utilise the prepareForSegue method thus, my problem may need a different approach.
I have a class called viewInits which holds properties in the .h file that I want allow other classes to set and get it's values. In this case, the property is an NSString *navBarTitle.
In ClassA, I have a tableView:didSelectRowAtIndexPath: method, where I
Create an ViewInits class object - *viewInits.
I then set the setNavBarTitle: to the value of [self.MenuRowsArray objectAtIndex:indexPath.row].
In the next line, I did an NSLog to check and yes, viewInits.navBarTitle now holds the value I desire.
In ClassB's viewDidloadMethod, similarly, I created a ViewInits object - *viewInits and did an NSLog check for viewInits.navBarTitle. But it returns (null). What seems to be the problem here?
Here is the code for how I'm trying to pass the NSString. What am I doing wrong?
viewInit .h
#interface ViewInits : NSObject
#property (strong, nonatomic) NSString *navBarTitle;
#end
ClassA.m tableView:didSelectRowAtIndexPath: method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = [self.MenuRowsArray objectAtIndex:indexPath.row];
UIViewController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
// *---------- Assign identifier to NSString viewInits ----------*
ViewInits *viewInits = [[ViewInits alloc] init];
[viewInits setNavBarTitle:identifier];
NSLog(#"%#", viewInits.navBarTitle);
// *---------- Assign identifier to NSString viewInits ----------*
[self.slidingViewController anchorTopViewOffScreenTo:ECRight animations:nil onComplete:^
{
CGRect frame = self.slidingViewController.topViewController.view.frame;
self.slidingViewController.topViewController = newTopViewController;
self.slidingViewController.topViewController.view.frame = frame;
[self.slidingViewController resetTopView];
}];
}
ClassB.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// *========== ECSlidingViewController ==========*
self.view.layer.shadowOpacity = 0.75f;
self.view.layer.shadowRadius = 10.0f;
self.view.layer.shadowColor = [UIColor blackColor].CGColor;
if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]])
{
self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Menu"];
}
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
// *========== ECSlidingViewController ==========*
ViewInits *viewInits = [[ViewInits alloc] init]; // Create ViewInit class object
self.navBar.topItem.title = viewInits.navBarTitle;
NSLog(#"%#", viewInits.navBarTitle); // <<--- This always ends up null. What's wrong?
}
Your help are much appreciated. Thank you.
If you want to use ViewInit as a common store of settings it should be a singleton so that all other instances in the app can get it. Currently you're creating a new instance each time you want to use it, so the new instance doesn't have any of your previous settings.
Aside, I know what the sliding view controller is, I ask about it because you may be using it incorrectly. If you have a view controller which is the current top view controller and it changes the top view controller (class A might be doing this, not sure) then the reference self.slidingViewController will stop working part way through your code.
In my app I habe a view controller that calls several views. All these views are UIViews. That works fine, but not in every case. One of the views that are called has some labels, textfields and two UITextViews. Everything is shown correctly but the UITextViews. The view is called in that way:
[[self view] addSubview:tasteView];
//tasteView = [[TasteView alloc] init];
[self setCurrentView:tasteView];
I call the init method of the view to display the UITextViews:
EDIT: After a comment of Phillip Mills this was slightly changed! Init isn't called anymore.
- (id)init
{
if (self)
{
[tv1 setNeedsDisplay];
CGRect frame = tv1.frame;
frame.size.height += 1;
tv1.frame = frame;
}
return self;
}
As I saw that setNeedsDisplay had no effect, I changed the size of the corresponsing frame to force a redraw. Unfortunately that had no effect, too.
Btw, the view is initially loaded in the viewDidLoad of the view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
[self setCurrentView:placeholder];
[self configureView];
wineryView = [self loadWineryView];
wineView = [self loadWineView];
tasteView = [self loadTasteView];
}
A method for loading the views looks like this:
- (UIView *) loadTasteView
{
NSArray *nibViews = [[NSBundle mainBundle] loadNibNamed:#"TasteView" owner:self options:nil];
UIView *tView;
for (id view in nibViews)
{
if ([view isKindOfClass:[TasteView class]])
{
tView = (TasteView*) view;
}
}
return tView;
}
I do not know why those UITextViews are not shown. Did I forget something? To show really everything, here are the connections that I made in InterfaceBuilder:
Does anyone know what I did wrong and can help me?
I think your initial code should be like this :
tasteView = [[TasteView alloc] init];
[[self view] addSubview:tasteView];
[self setCurrentView:tasteView];
addSubView after it is allocated
Hope it helps you
If you are creating the view in code (your first sample), alloc and init the view before trying to add it as a subview.
If you're loading it from another nib (last code section), you still need to add it to the view hierarchy.
So I have a method that sets an integer: -(void)setcurrentviewfromint:(int)currentint{ It is in a class called MyView. From my viewDidLoad method, I call it, and set it too 1:
currentview is of type int, created in my header file
- (void)viewDidLoad
{
[super viewDidLoad];
MyView *myview = [[MyView alloc]init];
[myview setcurrentviewfromint:1];
}
Then, in MyView.m, I have these classes:
-(void)setcurrentviewfromint:(int)currentint{
currentview = currentint;
NSLog("currentviewis:%d",currentview);
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
NSLog(#"drawRectCalled");
if (currentview == 1) {
NSLog(#"do something here");
}
}
}
But the debugger prints out:
2012-07-18 18:02:44.211 animation[76135:f803] currentviewis:1
2012-07-18 18:02:44.223 animation[76135:f803] drawRectCalled
But doesn't print "do something here". Any ideas why currentview doesn't equal 1?
First, about your question.
What datatype is currentview?
Second, it looks like your NSLog in setcurrentviewfromint: never gets called. If it was called, youd see "currentviewis:1" so make sure that is linking up correctly.
And, I must say, camel-case! Your method names are all lowercase and it's hard to read. :)
The issue is that the MYView you are setting is not the one you are reading currentView from.
In viewDidLoad you are creating a local variable myView and then setting its current view and then this myView becomes a memory leak as nothing points to it.
Assuming that MyView is the class the viewDidLoad is on and that currentview is an int attribute of that class (although the why is the method not setcurrentview:) . I would expect the code to be more like
- (void)viewDidLoad
{
[super viewDidLoad];
[self setcurrentviewfromint:1];
}
Thus setting the current view in itself
And as others state please use the Objective C standard of CamelCase