Linking storyboards elements to code - objective-c

On one of the scenes in my storyboard, i placed a button. It shows on the view fine.
The view itself is represented by class GameView, which contains both
IBOutlet UIButton *b;
#property (strong) IBOutlet UIButton *b;
I have connected the outlet to button from the storyboard's view.
From .m file of the GameView class, i:
[[self b] setFrame:CGRectMake(420, 260, 50, 30)];
[b setTitle:#"!!!" forState:UIControlStateNormal];
[self addSubview:[self b]];
When button is created programmatically, the following works fine
deal = [UIButton buttonWithType:UIButtonTypeRoundedRect] ;
[deal setFrame:CGRectMake(420,170, 50, 30)];
[deal setTitle:#"Deal" forState:UIControlStateNormal];
[self addSubview:[self deal]];
When program runs, however, the button from the storyboard is not seen. Why?

I am an epic newb. Posting the answer in hopes someone else might find it useful.
Basically, in my case, the view is created programmatically from the controller, whatever is seen on the screen of a storyboard is effectively replaced on object creation.
UIView *gameView = [[GameView alloc] initWithFrame:CGRectMake(0, 0, 480, 300)];
[[self view] addSubview:gameView];
Once i put IBOutlets into the Controller and added
[bb setFrame:CGRectMake(420, 260, 50, 30)];
[bb setTitle:#"---" forState:UIControlStateNormal];
[gameView addSubview:[self bb]];
It worked like a charm.

Related

add UIView as a subview in UITableViewController (or sliding up menu)

I am trying to add a subview in my UITableViewController. What I want to is when a user click a Navigation Bar Item, a small window or a subview will show which contains two buttons. When users click any button, the subview will disappear. I even have no success to add a subview in my TableViewController. I added following codes in ViewDidLoad:
UIView* simpleView = [[UIView alloc] initWithFrame:CGRectMake(0,200,300,100)];
UIButton* add= [[UIButton alloc] initWithFrame:CGRectMake(0,240,300,100)];
add.titleLabel.text=#"here";
[simpleView addSubview:add];
[self.tableView addSubview:simpleView];
which did not work, the error is
"setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key viewReference.'"
I change to [self.view addSubview:simpleView]; ,which still did not work
Can some one tell me how to add a subview in a UITableViewController and provide some sample code?
Thanks
Your button frame rect is incorrect so your simpleView is fully transparent. Change
UIButton* add= [[UIButton alloc] initWithFrame:CGRectMake(0,240,300,100)];
to
UIButton* add= [[UIButton alloc] initWithFrame:CGRectMake(0, 40,300,100)];

ARC and ViewControllers

I have a little misunderstanding regarding ARC. I'm creating a new UIViewController using the following code:
CGRect screenRect = [[UIScreen mainScreen] bounds];
LocationProfileView *locationProfile = [[LocationProfileView alloc] initWithLocation:l];
locationProfile.view.frame = CGRectMake(0, screenRect.size.height, screenRect.size.width, 400);
[appDelegate.window addSubview:locationProfile.view];
[UIView animateWithDuration:.25 animations:^{
locationProfile.view.frame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height);
}];
In its UIVIew I put a button which removes the view from screen. The problem with this is that locationProfile gets deallocated immediately after its being added to screen, so everytime I'm trying to tap on "Close" button (which calls a method in LocationProfileView class) my application will crash.
So I added a property:
#property(nonatomic, strong) LocationProfileView *locationProfile;
and changed the second line of code in:
locationProfile = [[LocationProfileView alloc] initWithLocation:l];
but now my class won't be deallocated until I initiate it again (because it loses the reference to the first instance of LocationProfileView?). What should I do to make my class being deallocated every time I tap on "Close" button? I guess that setting locationProfile to nil would work, but this means that I'll have to call a method in the main class (the one which contains the code block).
What is the proper way for doing this? Sorry if my questions is too noobish.
Note:
l is an instance of a custom class which contains some infos to be displayed in LocationProfileView's UIVIew.
- (void)closeButtonCallBack {
[self.locationProfile removeFromSuperview];
self.locationProfile = nil;
}
i am assuming the target of your close button is the viewcontroller itself
a strong pointer will the retain the object until the viewController itself is deallocated, unless you assign to it nil
a local variable will be deallocated when it goes out of scope
ALTERNATIVELY
without using the strong pointer, you can do this
LocationProfileView *locationProfile = [[LocationProfileView alloc] initWithLocation:l];
UIButton *close = [UIButton buttonWithType:UIButtonTypeRoundedRect];
close.frame = CGRectMake(0, 100, 100, 30);
[close addTarget:locationProfile action:#selector(removeFromSuperview) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:close];
In your original example,
LocationProfile *locationProfile=...
is a local variable. So it's released as soon as you return from the constructor. That's what you observed.
When you make it a strong property, the view controller retains the locationProfile:
#property(nonatomic, strong) LocationProfileView *locationProfile;

Create UIButton inside Objective C method

I am trying to create a UIButton in code, and this code is in some methods which will get called from some class.
Here is the method that creates the button
-(void)createButton
{
NSLog(#"createButton");
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"Get Friends" forState:UIControlStateNormal];
[button setFrame:CGRectMake(100, 100, 100, 50)];
[button addTarget:self action:#selector(loadTableView) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
but it never appears in the view, what's wrong?
Edit: if I call this method from viewDidLoad then it works!
Edit 2: the method is in the ViewController class and I call it from MyFacebooDelegate class
here is the call code from MyFacebooDelegate class:
ViewController *m2 = [[ViewController alloc] init];
[m2 createButton];
When you create a new ViewController using ViewController *m2 = [[ViewController alloc] init]; it is not the same ViewController that is handling the screen.
Instead of allocating a ViewController, you should be using the one that's created when the application starts.
May be your view is not loaded from Nib yet at the moment. If you created view by instantiating
[[UIViewController alloc] initWithNibName:#"someNibName" bundle:nil];
than view controller will be created and start to load view from Nib asynchronously. So, if UIViewController is instantiated, that does not mean UIView is. So, that's why your button work when created from -viewDidLoad: callback.

UIScrollView ScrollRectToVisible - not working with animate = yes

I have a UIScrollView which contains a button.
When the button is pressed, I would like to scroll to the bottom of the view using scrollRectToVisible.
eg:
CGRect r = CGRectMake(0, myUIScrollView.contentSize.height - 1, 1, 1);
[myUIScrollView scrollRectToVisible:r animated:YES];
If I set animated to NO, everything works as expected,
but if I set it to YES, I see really weird behaviour:
basically, nothing happens.
if I tap the button repeatedly, it may scroll a couple pixels,
or may scroll all the way.
but if I scroll the view manually with a finger before pressing the button,
it has a chance of scrolling to the bottom as expected, but it's not a sure thing.
I've printed _geScroll_Settings.contentSize, and it's as-expected.
I've also tried to delay the call to scrollRectToVisible by starting a timer, but the results are pretty much the same.
The scrollView is fairly vanilla.
I'm creating it in interface builder.
I am dynamically adding the scrollView's content at startup, and adjusting it's contentSize appropriately, but all that seems to be working fine.
Any thoughts?
My bet is that scrollRectToVisible is crapping out because the visible area is not valid (1x1), or the y offset is just outside the bounds, have you tried setting it with the size of the visible area of the scrollView instead?
CGRect rectBottom = CGRectZero;
rectBottom.size = myUIScrollView.frame.size;
rectBottom.origin.y = myUIScrollView.contentSize.height - rectBottom.size.height;
rectBottom.origin.x = 0;
[myUIScrollView scrollRectToVisible:rectBottom animated:YES];
Sorry I can't help you out more, but I'm not on my Mac right now, so I can't run a test. The code above would create a CGRect of the exact size of what fits inside the scrollView visible portion, and the offset would be the last visible portion in it.
I encountered a similar problem, including the "If I set animated to NO, everything works as expected" part.
It turned out that on iOS 6 the UITextView auto scrolls its nearest parent UIScrollView to make the cursor visible when it becomes first responder. On iOS 7 there is no such behavior. The UIScrollView seems to get confused by two calls to to scrollRectToVisible at about the same time.
On iOS 6 my explicit call to scrollRectToVisible is ignored most of the time. It will only scroll to make the first line of the UITextView visible (the auto scroll) and not the whole thing as it does on iOS 7.
To test it, make a new single view app in Xcode 5, set its deployment target to 6.0 and use the code below for the ViewController.m. Run it in the iOS 6.1 simulator, scroll to make the UITextView hidden and tap anywhere on the screen. You might have to retry it a few times, but in most cases it will only make the first line visible. If you re-enable the WORKAROUD define the UITextView gets embedded in its own UIScrollView and the call to scrollRectToVisible works as expected.
#import "ViewController.h"
//#define WORKAROUND
#interface ViewController ()
#property (nonatomic, strong) UIScrollView *scrollView;
#property (nonatomic, strong) UITextView *textView;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(viewTap)]];
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 240)];
self.scrollView.contentSize = CGSizeMake(320, 400);
self.scrollView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:self.scrollView];
#ifdef WORKAROUND
UIScrollView* dummyScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(20, 280, 280, 100)];
self.textView = [[UITextView alloc] initWithFrame:dummyScrollView.bounds];
[dummyScrollView addSubview:self.textView];
[self.scrollView addSubview:dummyScrollView];
#else
self.textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 280, 280, 100)];
[self.scrollView addSubview:self.textView];
#endif
self.textView.backgroundColor = [UIColor grayColor];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)viewTap
{
if (self.textView.isFirstResponder) {
[self.textView resignFirstResponder];
}
else {
[self.textView becomeFirstResponder];
}
}
- (void)keyboardWasShown:(NSNotification*)aNotification
{
#ifdef WORKAROUND
[self.scrollView scrollRectToVisible:CGRectInset(self.textView.superview.frame, 0, -10) animated:YES];
#else
[self.scrollView scrollRectToVisible:CGRectInset(self.textView.frame, 0, -10) animated:YES];
#endif
}
#end

Adding a subview without a XIB

This may seem painfully simple, but I'm just starting out so bear with me...
I have a main view with a toolbar. When the user presses a button in the toolbar, I would like a small prompt to appear at the top of the screen. I added a UIView within the existing UIView, and set it to be hidden. I connected that to an ivar called 'searchView' in my view controller, and tried the following:
searchView.hidden = NO;
When that didn't work I tried adding...
[self.view addSubview:self.searchView];
...which didn't work either.
Do I need to set the index somehow to bring it above the main view?
Is this approach just altogether wrong?
If you created the UIView from the interface builder, forget to use addSubview because interface builder it's doing this automatically.
To do that in graphical mode (IB), follow this steps:
Define an IBOutlet in your file "h" should be something like:
IBOutlet UIView * myHiddenView;
Then in IB, connect the IBOutlet that you have defined in the h file to the UIView that you have created graphically in the IB and give the hidden property to this UIView (checkbox).
Then in your button press method do this:
myHiddenView.hidden = NO;
If you prefer do it programmatically to copy this example code:
define in the interface of the .h file
UIView *myHiddenView;
after the interface in the .h file:
-(void)displayView:(id)sender;
then in the .m file:
-(void)viewDidLoad{
myHiddenView = [[UIView alloc] initWithFrame: CGRectMake (x, y, width, height)];
myHiddenView.hidden = YES;
[self.view addSubview: myHiddenView]
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(x, y, width, height)];
[button setTitle:#"button" forState:(UIControlState)normal];
[button addTarget: self action: #selector(displayView:) forControlEvents: UIControlEventTouchUpInside];
[self.view addSubview:button];
}
-(void)displayView:(id)sender{
myHiddenView.hidden = NO;
}