How to scroll to top a UIScrollView in ClassA from another ClassB - cocoa-touch

I'm completely new to Xcode and Objective C but managed to get a working prototype for an app by the help of this site. But at the moment I do not find any solutions for the following problem after nearly a day of research and trial&error.
I'm working with storyboards.
I have two classes: ClassA and ClassB.
ClassA has a containerView which holds another ViewController thats class is Class B.
This ViewController within the containerView holds an UIScrollView (defined in ClassB) which I want to be able to scroll to top from ClassA.
It works in the same class (ClassB) with this code...
[Scroller setContentOffset:CGPointZero animated:NO];
...but not from another class (ClassA)
How can I access the IBOutlet UIScrollView in ClassB from ClassA and tell it to scroll up?
Thanks so much for your help!

You have to define the iVar as #property:
#interface ClassB : UIViewController {
// don't define it here as iVar like: IBOutlet UIScrollView *Scroller;
}
#property (nonatomic, strong) IBOutlet UIScrollView *Scroller; // but define it here as property
You could then access the scrollView like this in ClassA:
[[instanceB Scroller] setContentOffset:CGPointZero animated:NO];
And like this in ClassB
[_Scroller setContentOffset:CGPointZero animated:NO];

Related

Change property class type in private implementation

I have a class on iOS which has a UIView property that other objects are able to read. For the sake of my internal implementation of this class, I want this view to be a custom subclass of UIView, but there is no need for the clients of this class to be aware of that. To them, this property should and will behave just like any other UIView.
Ideally what I want is something like this.
MyViewController.h:
#property (nonatomic, readonly) UIView *aView;
MyViewController.m:
#property (nonatomic, readwrite) CustomView *aView;
The compiler allows me to do this, but it doesn't actually understand what I want to do. It won't allow to message .aView as a CustomView object, it just lets me message it as a regular UIView object.
A workaround I have at the moment is to do this.
CustomView *newView = [[CustomView alloc] initWithFrame:CGRectZero];
[newView customViewMessage];
self.aView = newView;
Is there a better way to do this?
My preferred approach is to give the private property a different name. I then implement the getter for the public property and return the internal property's instance variable.
Example:
Class.h
#interface Class : NSObject
#property (nonatomic, readonly) UIView *aView
#end
Class.m
#interface Class ()
#property (nonatomic, retain) CustomView *cView;
#end
#implementation
- (UIView *)aView {
return _cView;
}
#end
Since you are using a view controller this is how you'd do it.
Step one.
Add a private property, for example
#property(nonatomic, readonly) CustomView *customView;
And override the getter to return the view.
-(CustomView *)customView{ return (id)self.view; }
This way you can use that property to call methods specific to your class without having to cast it every time, and any other objects can interface with your view controller's view in the same way they would with any other view controller.
Step 2
Since you are using a view controller there are two options:
You are instantiating the vc from a storyboard
In this case, you can select the view in Interface Builder and set it to a custom class. Done.
You are instantiating the VC from code
In that case, you have to override your view controller's loadView method and create your view in there:
-(void)loadView{ self.view = [CustomView new]; }

How can i make a UITabbar like this?

I would like to create a UITabbar like below but i don't know what is the logic to do that.
Here is the large answer:
First of all, you will need to create a UIView subclass to get a view that looks like the bar that you want. It can be composed by a background UIImageView and three buttons.
Then, the best thing would be to create a subclass of the UITabBarController and in its viewDidLoad or at any point where the flow will go through just once, you instantiate one view of type specified at first point. You should place the frame of this view in order to hide the original tabbar of the controller.
This would be the custom bar header file:
#interface CustomBar : UIView
{
}
#property (nonatomic, retain) UIImageView *backgroundView;
#property (nonatomic, retain) NSArray *buttons;
#end
You can easily complete the implementation. You can try to look for how to instantiate it with a nib file to make it easier to design it. In order to test, you can first just set the background color to green or something visible.
Then, this would be the subclass of the UITabBarController class:
#interface CustomTabBarController : UITabBarController
#property (nonatomic, retain) CustomBar *customBar;
#end
#implementation CustomTabBarController
- (void)viewDidLoad
{
[super viewDidLoad];
self.customBar = [[[CustomBar alloc] initWithFrame:[self.tabBar frame]] autorelease];
[self.view addSubview:self.customBar];
}
#end
Please, remember to implement the dealloc if you are not using ARC.
The thing I am not sorting out here is how to create the communication between the buttons from the custombar and the tabbarcontroller. This should be solved by delegates. If you need help with that, I will complete that too.
Good luck!

Access a UITextField in another UIViewControllers view

This is how I use a XIB view controllers view as a subview in the MainViewController:
UIViewController *nameController = [[NameSubViewController alloc] initWithNibName:#"NameSubViewController" bundle:nil];
nameSubView = [nameController view];
[self.view addSubview:nameSubView];
The nameController view contains a UITextField property. Can I somehow access this property from MainViewController?
EDIT:
If I create a property for the textField in the View Controller too, I'm still not able to get it in MainViewController. Think it's because of the UIView subclassed causing problems?
NameSubViewController.h:
#import <UIKit/UIKit.h>
#interface NameSubViewController : UIViewController
#property (nonatomic, strong) IBOutlet UITextField *textField;
#end
NameSubView.h:
#import <UIKit/UIKit.h>
#interface NameSubView : UIView
#property (nonatomic, strong) IBOutlet UITextField *textField;
- (IBAction)textFieldReturn:(id)sender;
#end
Connections in IB for NameSubViewController:
Connections, NameSubViewController
Connections in IB for NameSubView:
Connections, NameSubView
Did you create an outlet for the textfield in your nameController? Do that, and then you can retrieve the value using
nameController.textField.text
In the nib file, click on the file's owner icon (on the left of the nib), and set it's class to your UIView's subclass using the inspector on the right.
Why are you adding view from Controller A in Controller B. Isn't it better that you create a view by only using its xib file and add that view to your controllers view.
For accessing field, you can assign a tag to your textfield, and where ever in your code you need it, call
self.view viewWithTag:<#(NSInteger)#> method.

IBOutlet in ARC releases and sets to nil. How to avoid this? objective c

I'm new to ARC and Storyboarding. I've set IBOutlet to UITableView from my UIViewController.
After some time my IBOutlet sets to nil and I can't reload it from other classes.
Here is my dataTable IBOutlet:
#property (weak, nonatomic) IBOutlet UITableView *dataTable;
At the start dataTable is not nil, but not when I try to access it from another class (via appDelegate). How to solve this problem?
UPDATE
I call this method from my UIViewController
[appDelegate.myClass loginWithUserName:loginField.text andPassword:pwdField.text];
When it's done, and I have data to show, I call this code from loginWithUserName method:
MyViewController *controller = [[AppDelegate sharedStoryboard] instantiateViewControllerWithIdentifier:#"MyViewController"];
[controller audioLoaded];
And here is that method in my UIViewController, wich reloads data
-(void) audioLoaded
{
//it is nil here
[self.dataTable reloadData];
}
Set the property to strong retain the object:
#property (strong, nonatomic) IBOutlet UITableView *dataTable;
It's not good practice to access a UITableView from another view controller though..
EDIT:
You shoul reconsider the whole approach, by moving that logic from your appdelegate to a dedicated class that will perform the login. You can create a simple protocol that the UIViewController with the table can implement, then, when calling the login method, pass a reference to the current viewcontroller, something like
loginWithUserName:andPassword:andCaller:(id<LoginDelegate>)sender
Where LoginDelegate is something on this line:
#protocol LoginDelegate
- (void)audioLoaded;
#end
In this way you can just call
[sender audioLoaded];

How do I assign a delegate in a view for a control contained in a child view?

I have a view controller which contains a UISearchBar
#interface TradeFindHeaderViewController_iPhone : UIViewController {
UISearchBar *searchBar;
}
#pragma mark - Properties
#property (nonatomic, retain) IBOutlet UISearchBar *searchBar;
#pragma mark - Methods
-(void) configureSearchBar;
#end
This controller is then initialized and stored in a property of another controller.
#interface TradeFindViewController_iPhone : TradeFindViewController<UISearchBarDelegate> {
TradeFindHeaderViewController_iPhone *_headerController;
}
#pragma mark - Properties
#property (nonatomic, retain) TradeFindHeaderViewController_iPhone *headerController;
#end
I want this TradeFindViewController_iPhone to receive the UISearchBar delegate events so I assign it's delegate
-(void)configureTableHeader{
self.headerController=[[TradeFindHeaderViewController_iPhone alloc]initWithNibName:#"TradeFindHeaderView_iPhone" bundle: nil];
self.headerController.searchBar.delegate=self;
self.tableView.tableHeaderView=self.headerController.view;
}
However, the UISearchBar delegate events are not being called. Have I assigned the delegate properly given the UISearchBar is in the contained view?
I would probably implement a multi-level delegate system. Your TradeFindHeaderViewController_iPhone class would register as the delegate for the UISearchBar, and would then call a delegate method in your TradeFindViewController_iPhone class.
This solution helps to keep the whole design very modular, and also prevents things breaking (changing the name of objects) across classes.
This should solve your issue with the delegate methods not being called.
Hope this was of some help.
Josh