#Synthesize IBOutlet (UIScrollView) not working - iphone

This is about an outlet not synthesising correctly (UIScrollView)
In one particular case, i have an interface declared as:
#interface VC_Create_Preview : UIViewController <UIScrollViewDelegate> {
UIScrollView *scrollView;
}
#property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
And in the implementation....
#synthesize scrollView;
But in debug mode i see that my self->scrollView always has a 0x0 next to it.
Performing operations like
CGRect frame = scrollView.frame;
always returns a origin, height, width of zero (i suspect because it did not synthesise correctly)
Does 0x0 mean that it does not point to any location in memory?
Does this mean that it did not synthesize correctly?
Could it be that there is a broken link somewhere from the outlet to the scrollview in IB?
Cheers
Kevin

Make sure that you actually connected a UIScrollView to the outlet.
Keep in mind that scrollView won't be set until after the view has been loaded from the nib.

0x0 means a null pointer, you probably have not tied the scrollView to a scroll view in IB...This means having the viewControllers nib have a scrollView in its view and tied to the outlet.

If you want to work with outlets and use there real size that user will see (include navigation bar, tab bar, etc.) you must implement all UI changes at viewWillAppear or viewDidAppear.
Read more about stages of loading view from nib.

Try removing local declaration of scrollview i.e.
#interface VC_Create_Preview : UIViewController <UIScrollViewDelegate> {
UIScrollView *scrollView;//remove this
}
It may help you. Also while allocating use _scrollView instead of scrollView.

Be sure that you are using the correct class in your code, for example, the first UIViewController you drop into storyboard will have the generic "whateveryourprojectiscalled" UIViewController.
However, the problem for me was that I then had that linked to several other UIViewController, none of which had there own class declared, so the scroller outlet I was writing, is only showing up on the main original UIViewController which is not where I needed it to be. So once I wrote a Custom Class name, and then re wrote the code to accommodate that. The outlet appeared perfectly and worked fine.

Related

getting the container/UIViewController of UIView

So I have a UIViewController A which adds a UIView B as a subclass. The UIView B has a UITableView. I want the UITableView scrollView delegate to be in the UIViewController A. How do I do this? As of now the scrollViewDidScroll delegate is inside this UIView class. Is there a way so that the scrollViewDidScroll is inside viewController A and is called whenever the UITableView in the UIView is scrolled?
Make the tableView as a property accessible from the outside. Than you could set it up in your ViewController A like that:
// ClassB.h
#property (nonatomic, readonly) UITableView* tableView;
// In your UIViewControllerA.m
// in loadView: or anywhere else
self.viewB.tableView.delegate = self;
So result is: your ViewController is the delegate.
The scroll view and the table view are the same object -- notice that UITableView is a subclass of UIScrollView. That object has only one delegate, not separate delegates for the table stuff and for the scroll stuff. Also notice that UITableViewDelegate adopts UIScrollViewDelegate. So, the object you set as the table's delegate will also get UIScrollViewDelegate messages.
Now, there's no reason that your table's delegate can't forward messages about scrolling to some other object. You'd have to set that up yourself, of course. So, when B gets a -scrollViewDidScroll: message, it might send an equivalent message to A, or whatever. I'd think twice before actually doing that, though... I'd try to have just one object (the view controller) be responsible for everything related to the table.

Using UISegmentedControl to switch between two views

I created a subclass of UIViewController. In it I have two properties of:
#property (nonatomic, retain) IBOutlet UIView *presetsView;
#property (nonatomic, retain) IBOutlet UIView *customView;
I added a new UIView to my .xib and put some UI elements in it. I want to hide one view, and show the other based on when the UISegmentedControl is pressed.
My question is in Interface Builder, my original View that was provided me by IB, has an outlet connected to it already to File's Owner. Because I have my own two views, presets and custom, how do I make the outlet connections in IB?
I tried deleting the original view that was provided by IB and dragged two new UIViews to the canvas. I then connected an outlet to each. When I push my new viewController, I get an error that there is no view for my viewController. Then when I connect the File's Owner to the "view" outlet that shows up for the view I want to show first, the application runs. I wasn't sure if this was the correct way, and why it would be the correct way. Does the ViewController always need a .view property an outlet to it? Is that why I needed to do this? Thanks.
Write action method for UISegmentedcontrol and implemnt method like below
-(IBAction) selectMessageType {
noResultsPriview.hidden = YES;
//[activityIndicator startAnimating];
switch (msgOptionControl.selectedSegmentIndex) {
case 0:
//code for view1
break;
case 1:
//code for view2 break;
case 2:
//code for view3
break;
case 3;
//code for view4
break;
default:
break;
}
}
Yes every UIViewController has a single root view. It must be able to construct that view when its -loadView method is called either by loading that view from a nib file (and setting its view property as a result) or by creating it programmatically.
In your case leave the view property view alone and don't try to swap that around. This root view will have already have been added to the window and changing the controller's reference to point to some other object will just cause confusion and undefined behavior. Instead add both of your views as subviews of the controller's root view and hide or show then as needed.
UIViewController must have a valid UIView so in your case it can be the original UIView created during the XIB creation. Your two UIView properties are correct. All you have to do is to setup in IB the connection between your presetsView and the original UIView so that you can later switch back to it, then you need to connect customView to your other UIView.
So after you finish your original UIView will have two connections, one as a view of UIViewController (owner) and one as a presentsView.
Those connections are only pointers so that you can use them to manipulate objects in the UIViewController.

Custom UIView from outlet

I know this has been discussed a number of times but I still have some problems getting around the problem, so any help would be appreciated. I have a class MyView which subclasses UIView. So far so good, in this custom class I basically configure the layout, UI, etc.
Now, I have a separate UIViewController and what I want to do is create an outlet for that custom view. In the view controller's Nib I set the view's class to that of my custom view and connect it to the outlet, but I can't see anything apart from a blank view.
How and where do I load the view from nib? Do I simply say self.theOutletForMyCustomView = load from nib or is it something else? Thanks for your help
First of all, you have to set the name of your CustomView inside your UIViewController nib file like that
Then, you have to retain your property like that inside your UIViewController interface :
#property (nonatomic, retain) IBOutlet CustomView *myCustomView;
or an ivar should work, but assign an IBOutlet property doesn't work.
And if you customize your CustomView inside your CustomView class implementation. Beware of doing your initialization in awakeFromNib or initWithCoder: instead of initWithFrame:

Add subview to tableview which doesn't scroll

I'm using a UITableViewController and want to add a searchbar.
My options are [self.tableview addSubview:searchBar] or self.tableview.tableHeaderView = searchBar
Both options will scroll the searchbar along the rest of the tableview, which I understand. But is there a way to lock elements up, instead of using a UIViewController or changing the frame origin on scroll?
I'm thinking of a way to get above the current view hierarchy and add a subview onto that.
I tried the opposite approach, to add a view to the superview and bring that to front
[[self.tableView superview] addSubview:searchBar];
[[self.tableView superview] bringSubviewToFront:searchBar];
}
but it didn't work.
UITableViewControllers are UIViewControllers that have their main view property being an UITableView. Thus this UITableView do takes all the screen.
The approach you are looking for is to use a standard UIViewController whose view is a standard UIView, and add your UISearchBar and the UITableView as a subview to it in IB.
To do this, simply:
Change the class of your view controller and instead mention that it conforms to the tableview-associated protocols : change #interface UITableViewController to #interface UIViewController <UITableViewDelegate, UITableViewDataSource>
Add a #property(nonatomic, retain) IBOutlet UITableView* tableView property to your header file, and the associated #synthesize tableView; statement in the implementation. Don't forget to set this property back to nil (self.tableView = nil) in your dealloc for good memory managment
Link your UITableView instance in InterfaceBuilder to this newly created IBOutlet.
Thus you still have a UITableView but this won't be the main view that takes all your screen; instead you can layout your tableView like you want and make it take only a part of your screen, and position the UISearchBar above it.
Another approach would be to use the UISearchDisplayController to manage your UISearchBar.

Adding UIView subview to single table view controller in navigation stack

I'm working on an app that has three table view controllers in a navigation stack. The root view controller and the second VC have toolbars, but I want to add a subview to the second view controller like this. (The color is just there for visualization.)
I want to add the view programmatically, since I haven't been able to do it with IB without major headaches. Right now, I've been able to kind of get what I want by drawing a UIView in the second view controller like this:
- (void)viewDidLoad {
[super viewDidLoad]
UIView *detailView = [[UIView alloc] initWithFrame:CGRectMake(0, 392, 320, 44)];
detailView = [UIColor redColor];
[self.navigationController.view addSubview:detailView];
[detailView release];
}
The problem with this approach is that once the UIView is loaded in the second view controller, it stays loaded and is drawn in the third and root view controllers. I've tried a variety of methods of removing the UIView, including setting the detailView to nil in viewDidUnload, calling removeFromSuperview in didSelectRowAtIndexPath (which removed the view from the whole stack).
I've also tried adding the subview to self.view, but that pushes it below the visible area of the table view, so I have to scroll up to see it, and it snaps back down when I let go.
Clearly, adding this subview to the navigation controller is not the best way to do what I want, but I'm at a loss as to where to go from here.
As you've already discovered, you definitely should not be reaching up into the navigation controller's view.
You want your SecondViewController to be an UIViewController that implements the UITableViewDelegate and UITableViewDataSource and whose view lays out the UITableView and the UIView you wish to use for your stationary 'footer' in it's own main UIView.
It helps to keep in mind that UITableViewController is ultimately is just a convenience for creating a view controller whose view consists entirely of a UITableView.
Anyway, rather than attempt to put a pile of that code inline in this answer, you can browse it (or svn co) from this read-only svn repo.
EDITED (now that it's not midnight, putting some code/explanation directly in answer):
For the controller to be pushed onto the nav stack that needs the footer create a new UIViewController-based class (do NOT check the 'UITableViewController subclass' box in the template selection dialog).
Add instance variables for the UITableView and the UIView that is to be the extra bottom view.
#interface SecondViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
UITableView* tableView;
UIView* customFooterView;
}
#property (nonatomic,retain) IBOutlet UITableView* tableView;
#property (nonatomic,retain) IBOutlet UIView* customFooterView;
#end
In IB add a UITableView and UIView to the existing root view for the controller and lay them out as desired (probably worth altering the auto-resize parameters too if your app can be used in both landscape and portrait). Hook up the two views to the outlets defined for them in the "File's Owner" and also ensure you hook up the UITableView's delegate and dataSource properties to point at the "File's Owner."
Then just implement the UITableViewDelegate and UITableViewDataSource protocols as appropriate for your application.
If you want to lay out the entire 'footer' view in IB then go right ahead. Otherwise you can easily add items programmatically in viewDidLoad (and remember to tear it down in viewDidUnload).
I don't like the approach. You should put your table view inside another view, and put your detail view together in that view.
Despite of that, I think you can remove your view in viewWillDisappear method of your view controller. I also notice that you did not keep your detailView as a private variable, which you should do because you need to reference it when removing it later (I still wonder how you have done it.)
Note that viewDidUnload is called in case of view unloading (i.e. releasing from its controller), so it is not related to navigation.
Not sure which behavior you're looking for but try one of these:
Assign the detailView to the tableFooterView property of the tableview on the second VC.
Reduce the height of the table view and add the detailView to self.view.