Can I use properties to determine the class of an object? - objective-c

I have a custom UITableViewCell created in IB.
All my cells will have this general layout. However,in some cells, the two white views will be classA and in other cells the two white views will be classB. (Both subclasses of UIView). I tried to assign the specific subclass of the two views using properties.
I set the two views as properties of the cell
#property (nonatomic, retain) IBOutlet UIView *leftView;
#property (nonatomic, retain) IBOutlet UIView *rightView;
And in my view controller where I make the table view, I tried creating an object of type subclassA and assigning it as leftView, so that leftView will be of type subclassA. In other cells, I would create an object of subclass B and set it to leftview, so that in those cells, left view would be of subclass b.
//equationTextField is a subclass of UIView
EquationTextField *textField = [[EquationTextField alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; // arbitrary frame
cell.leftView = textField;
This code doesn't work, however. Is there a better way to assign the specific class of my views?

What you are doing is fine, but you may want to investigate having two different cell types (with your custom views already embedded) to improve performance - each could have a different reuse identifier which you would choose depending on the index path. Creating views every time in cellForRowAtIndexPath is never a good idea.
You could even derive both types from the same cell, just use the different reuse identifier and add in the correct subclasses only when first creating the cell.

You can check to see if cell.leftView is your EquationTextField if needed:
if([cell.leftView isKindOfClass:[EquationTextField class]]) {
NSLog(#"View is EquationTextField");
}
else {
NSLog(#"View is not EquationTextField");
}

Related

How to set UITableViewController custom class programmatically?

This is my storyboard:
The UITableViewController, has a generic UITableCell (MMSwitchTableCell) that has an image, a label and switch.
The idea is to be able to create different UITableViewControllers that present different data with the same layout i.e with the same cell object and same behavior. for example one time the UITableView has a list of cells that helps you select fruits, second UITable helps you select furniture.
The two UITablesViewController have no relation between them (no inheritance or aggregation), they are different instances in different viewControllers, I only want to re-use the designed control and the UITableCell code.
So my code has a UIViewController where I declare a property:
#property (strong, nonatomic) MMGoSeePopoverTableViewController* goSeePopoverTableViewController;
and lazy load it:
-(MMGoSeePopoverTableViewController*) goSeePopoverTableViewController
{
if(_goSeePopoverTableViewController == nil)
{
_goSeePopoverTableViewController =(MMGoSeePopoverTableViewController*)
[self.storyboard instantiateViewControllerWithIdentifier:#"switchPopover"];
}
return _goSeePopoverTableViewController;
}
and a second UIViewController in which I declare a property:
#property (strong, nonatomic) MMLayersPopoverTableViewController* layersPopoverTableViewController;
and lazy load it:
-(MMLayersPopoverTableViewController*) layersPopoverTableViewController
{
if(_layersPopoverTableViewController == nil)
{
_layersPopoverTableViewController =(MMLayersPopoverTableViewController*)
[self.storyboard instantiateViewControllerWithIdentifier:#"switchPopover"];
}
return _layersPopoverTableViewController;
}
In the storyboard I've set the custom class to MMLayersPopoverTableViewController, instead I wish to leave it blank and somehow set it in the code. I guess I should do this inside the lazy loaders, but I can't figure how.
Edit
The suggested "This question may already have an answer here:" is not the same as what I'm asking. I have amended the post to explain my problem better.
The idea is to be able to create different UITableViewControllers that
present different data with the same layout i.e with the same cell
object & same behavior.
This sounds like a case where you should use a .xib file instead of a storyboard. The advantage of storyboards compared to .xib files is that you can see the structure of the app in terms of views and the corresponding view controllers. In your case, though, you're trying to reuse the same view with different view controllers. Putting your table in a .xib file that's owned by the view controller will let you load the same table, cell, etc. with whatever view controller you decide to instantiate.
In your .xib file, set the type of the File's Owner proxy to some common superclass of all your view controller classes which contains all the necessary functionality. For example, if all your view controllers are derived from UITableViewController and you don't need any special outlets, set the type to UITableViewController and connect the table to the proxy's tableView outlet. If your view controllers have other common behavior, put all that in a subclass of UITableViewController, use that as the proxy's type, and derive the other view controllers from that class.
Once you've done all that, you can use the -initWithNibName:bundle: method to initialize any of your view controllers and load the same view:
// in one place...
MMGoSeePopoverTableViewController *goSeeVC = [[MMGoSeePopoverTableViewController alloc]
initWithNibName:#"CommonTableView.xib" bundle:nil"];
// and in some other place...
MMLayersPopoverTableViewController *layersVC = [[MMLayersPopoverTableViewController alloc]
initWithNibName:#"CommonTableView.xib" bundle:nil"];

TableViewController within a ViewController

I have a UIViewController (StoreViewController), and in it's .xib is a UITableView to the left, and a standard UIView to the right. I have created a UITableViewController called StoreTableController and want to somehow make it the the controller of the table view within the StoreView.xib.
Unfortunately, I need to keep the File Owner of the nib file as StoreViewController. I have a delegate within the StoreTableController which has been set as the StoreViewController (this is for calling certain methods), and within the StoreViewController I have an instance of the StoreTableController.
So far I have tried keeping an outlet of the UITableView within StoreViewController and then doing this:
[self addChildViewController:self.tableController];
[self.tableController setTableView:self.table];
[self.table setDataSource:self.tableController];
[self.table setDelegate:self.tableController];
Where self.table is the outlet, and self.tableController is the instance of the StoreTableController.
However, I do not fully understand how to use UIViewController containment, so this is obviously incorrect.
I have tried variations of this as well, but really don't know what to do.
I have avoided using a UISplitViewController here because not only is the left view larger than the right, but also there are various things I plan to do which mean this must be done in a single .xib file if possible.
Any help is very much appreciated.
First, put a regular UIView instead of a UIScrollView in your .xib. Connect it with an IBOutlet called "tableContentView".
Then, create a new instance of UITableViewController (or your custom class, derived from UITableViewController) in your code, and add its UIView to the tableContentView like so:
- (void)viewDidLoad
{
[super viewDidLoad];
// Add tableView
UITableViewController *someTableViewController = [[UITableViewController alloc] init];
someTableViewController.view.frame = self.tableContentView.bounds;
someTableViewController.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.tableContentView addSubview:someTableViewController.view];
}

Custom Keyboard on iOS: How do I access the UITextField?

I have a UIView subclass that I assign to a text field as follows:
self.textField.inputView = [[HexKeyboard alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
and this works (i.e., the keyboard comes up). However, how should the HexKeyboard instance know about the textField?
[Of course I can add a property to the HexKeyboard to achieve this (and call it delegate), but I figure there's a built-in mechanism for this...]
You don't really need a complex delegate pattern for this. Just create a property of type UITextField on your HexKeyboard class, and make it an unsafe_unretained reference so you don't get a retain loop:
#interface HexKeyboard
#property (nonatomic, unsafe_unretained) UITextField *textField;
#end
Then set it when you set your inputView:
self.textField.inputView = [[HexKeyboard alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
self.textField.inputView.textField = self.textField;
There seems to be no built-in mechanism for this, as the other answerers have pointed out. As Nick says, you don't need a complex delegate pattern for this. Or rather, you use the delegate pattern, but you get the delegate class for free. In this case it's the UITextInput protocol.
So your keyboard probably looks like this (and has a NIB)
#interface ViewController : UIViewController
// use assign if < iOS 5
#property (nonatomic, weak) IBOutlet id <UITextInput> *delegate;
#end
When you create the keyboard controller, you assign the UITextInput conformer to it, so something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
HexKeyboardController *keyboardController = [[HexKeyboardController alloc] initWithNibName:#"HexKeyboardController" bundle:nil];
self.textField.inputView = keyboardController.view;
keyboardController.delegate = self.textField;
}
However, I thought, there MUST be a way to define this keyboard just once and get the keyboard to "automatically know" who the UITextInput object that summoned it is. But I've looked around to no avail... you cannot figure out who the firstResponder is unless you troll the view hierarchy yourself or retain your delegates in a list (which would cause a retain loop). Plus, this isn't so bad because the HexKeyboardController will unload, too, when the textField is dealloced.
I dont believe there is a built in mechanism for this, you probably want the a delegate in the hex keyboard that will receive the "keystrokes" from it and then append it to the textfield, or whatever it is you need to do..

Pass data to UITextField between ViewControllers

I am stuck on passing data from one ViewController to another. The scenario is as:
I have 2 ViewControllers named : SearchDomainController and LoginViewController. What i am trying to do is pass the string value from SearchDomainController to the UITExtfield in LoginViewController.
In LoginViewController i have declared IBOutlet UITextField *domainField; and also a property #property(nonatomic,retain) UITextField *domainField.
The problem is when i create a new instance of LoginViewController in SearchDomainController and try _loginViewController.domainField.text = #"Some text";
the text never changes in UItextField on LoginViewController.
What did i miss ? And what are the best solution for this kind of problem? Thanx
My guess would be that _loginViewController.domainField is nil at that time, which is probably because the view hasn't loaded yet, and the label is created when the view loads (via a nib) and not as soon as the view controller object is created.
In order to not depend on having the view fully loaded when passing the value, I would have used a separate property for passing along the title, i.e. _loginViewController.domainFieldText = #"Some text";. Then in viewDidLoad of the _loginViewController, assign the value of domaonFieldText to the actual label.
Alternatively, make sure the UILabel instance is created and not nil when you set its text from the other view controller.
Set the string as a property of the AppDelegate in one view controller, and you can retrieve it from another, and set it as textField.text

In iOS, how do I reference an object in a view that is created with a xib file?

I have a view controller that is instantiated in appDelegate and pushed onto a navigation controller. The view controller's view is created with a xib file. The xib file puts a UILabel on the view (among other things). Now I need to set the label's text property programatically but I don't see how to get a reference to it. How do I reference the label object?
I'm using xcode 3.2.5 and building an iPad app.
Aside from IBOutlets, you can also set a tag property on the label in the IB. Then, when you need it you can do:
UILabel *label = (UILabel *)[self.view viewWithTag:111];
111 of course being the tag you assigned to the label in IB.
You do this with what's called an "outlet". You define them in your controller, mark them clearly as IBOutlet and then connect them in Interface Builder to your file owner (or other delegate object created in IB).
For instance, in your FooController.m you might have this:
#interface FooController ()
#property (nonatomic, weak) IBOutlet UILabel* fooLabel;
#end
Then you would select your label, and either control drag from it to the file owner, or go to its connections tab, and drag from the + under referencing outlet, to the file owner and select the fooLabel.
UPDATE: Code sample changed to reflect modern way of handling this case.
[self.view viewWithTag:NUMBER_OF_TAG]; does the trick. But remember that if you want to access the view you must do it on the viewWillAppear or viewDidAppear events.