How to pass values from a subclass of UIView to UIViewController class - ios

I have a class Graph that subclasses UIView.
I am in my view controller class and I call the SliderView class with the following code
- (void)viewDidLoad
{
[super viewDidLoad];
if (self) {
// Custom initialization
SliderView = [[SliderView alloc] init];
}
[self setView: SliderView];
}
I'd like to be able to access to the properties I have setup in SliderView in my view controller class. How can I do this?

Use the getters and setters like Kyle said (he just went further showing the property).
[graph propertyName] and [graph setPropertyName:newValue]
I would also take a look at: http://cocoadevcentral.com/d/learn_objectivec/

You should just be able to access the properties of the Graph class. In your Graph class you might have some thing along the lines of:
#property (nonatomic, strong) NSObject *propertyName;
You would access it in the UIViewController by way of something like
[(Graph *)self.view propertyName];

Related

what is difference between View controller and class

This Is my class.h
#import "BankAccountDetails.h"
static int openAccounts = 0;
#implementation BankAccountDetails
+(BankAccountDetails *) newAlloc{
openAccounts++;
return [BankAccountDetails alloc];
}
+(int) totalOpen{
return openAccounts;;
}
And This Is my ViewController.h
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize lbl;
- (void)loadView{
[super loadView];
NSLog(#" 1 LoadView Calling");
}
- (void)viewDidLoad {
[super viewDidLoad];
lbl=[[UILabel alloc] init];
lbl.backgroundColor = [UIColor redColor];
lbl.text = #"hello frnd i'm making a lable ";
[self.view addSubview:lbl];
Please see this Question carefully and My Question is , Actually i m confuse I want to know Difference Between Class.h and controller.h While both are Class.
Class is an abstract word which is used by people like us (Programmers) to make represent real entities into a digital world.
So that all views, objects and controllers can be common called as Class.
So view controller is a type of class which is a controller for a view to manage view and its subview and related actions on it.
The main difference in your both class is both have different methods.
I mean class.h has class methods. Class methods are the methods which can called with out creating object of the class. You can simply call it by using just class name.
For example:
int total = [BankAccountDetails totalOpen];
And ViewController.h class contains instance method, to call these methods an object of class is required.
For example:
ViewController *controller = [ViewController alloc] init];
[controller openAccount];
Point to be note here
You have written -viewDidLoad() method, So ViewController class must be extend with UIViewController class otherwise it will gives you an error.
It's a convention to name the files as [class name].h
And in case of categories [class]+[category].h
In your case the ViewController.h you posted is actually ViewController.m (which is the implementation file, not the interface, "h" stands for header file).
A ViewController class extends UIViewController class and you can go down the hierarchy path to the root class which is NSObject.

How to create a custom base class which has a TableView, a Search & some edit functions, so as other class can inherit from it

I have many UITableViewController classes in my project. They have,
Mostly the similar functions including search, edit, pull to refresh.
A TableView
A UISearchBar
A UISearchDisplayController.
As I don't want to re-write all these functions each class, how do I create a custom base class that has all these function.
I don't know how to do this?
Any tutorial link or some guidance will be of much help.
You need to follow simple inheritance concept of OOPS.
So here is a simple idea to proceed.
Create an new file, Name it like myCustomTableBase & type UITableViewController in SubClass of section in that dialog.
Now provide all your table related stuff & public method & objects in this base class.
Now create a new file again like step1 & name it like myNewHomeController & type myCustomTableBase in SubClass of section in that dialog.
Once you are done with this file, you can check the myNewHomeController.h file for the inheritance path like this:
#import "myCustomTableBase.h"
#interface myNewHomeController : myCustomTableBase
#end
Now its up to you how you design you base & subsequently inherit (subclass) your child classes out of it.
hope that helps.
UPDATED CODE
Please note: Here the base call is derrived from UIviewController, not the UITableViewController
BaseViewController.h
#interface btBaseViewController : UIViewController {
UITableViewStyle _tableViewStyle;
UISearchDisplayController *_searchController;
}
#property (nonatomic, strong) UITableView *tableView;
#property (nonatomic, strong) UISearchBar *searchBar;
-(void)renderPadUI; // should be implemented by derived class
-(void)renderPhoneUI; // should be implemented by derived class
BaseViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[self renderUI];
}
-(void)renderUI{
// Do any additional setup after loading the view.
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
if(IS_IPAD) {
[self renderPadUI];
}else {
[self renderPhoneUI];
}
}
-(void)enableSearchSetUp:(BOOL)show {
_searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.view.bounds.size.width, 0)];
_searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_searchBar.delegate = self;
_searchBar.placeholder = #"Search any keyword";
[_searchBar sizeToFit];
// Create search controller
_searchController = [[UISearchDisplayController alloc] initWithSearchBar:_searchBar contentsController:self];
_searchController.searchResultsDataSource = self;
_searchController.searchResultsDelegate = self;
_searchController.delegate = self;
// add tableView
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) style:_tableViewStyle];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
[self.view addSubview:_tableView];
// This is important line
_tableView.tableHeaderView = _searchBar;
}
Now in any of your derived class from this class say btHomeViewController
btHomeViewController.h
#import "btBaseViewController.h"
#interface btHomeViewController : btBaseViewController
#end
btHomeViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
// you need not to call this method from this class. The base/parent class will invoke this method, as soon as you create the instane of this class.
-(void)renderPhoneUI {
[self enableSearchSetup:YES]; // this will base version
}
Also
note that you have to implement the -(void)renderPhoneUI method as the base class is expecting child to implement this. Or else remove it from base then.
you have to implement the delegates & dataSource for UITableView & UISearchBar, because I haven't provided any implementation of it in base. If you make give implementation of delegates in base class, then derived class can refer the same delegate's if not specifically implemented in derived class.
IS_IPAD is a custom Macro to detect the device version using UIDevice class. Search about it, you will get its definition.
this approach gives to a single code that handles TableView implementation with search which is in base class. If you want any customization to tableView & search bar in derived class, then you can do that the customization in specific class's renderPhoneUI method.
I would suggest to implement all the delegates in base class itself. Then all you tableView & search, across app will be consistent. Just keep playing/updating with dataSource.
If your tableview is different for each class, in terms of cellForRowAtIndexPath implementation, then provide an implementation of cellForRowAtIndexPath method in the intended class.
Here is sample code.
I hope I have made more of the things clean & clear.
hope that helps.
The better way of doing this is , Create a Super class Say BaseTableViewController implement your base functionality in this class, and inherit other UITableViewController Classes from this Class. Like
#interface BaseTableViewController : UITableViewController
- (void)doSomething
#end
And, Your other UITableViewController Classes should be like
#interface FirstTableViewController : BaseTableViewController
And call [super doSomething];

iOS Subclassing a Custom Class

I'm having trouble wrapping my thoughts about class inheritance. I'm suppsed to create a dashboard like interface in a app, and I'll have maybe 10 widgets/dashlets on that dashboard view. All those dashlets/widgets will have basically same look, with a title on the top, borders, row of buttons on the top and a graph.
Let's say I create a subclass of UI View called 'Dashlet' with properties and outlets, and create XIB file with proper layout and connected outlets etc.
Now I want to create several subclasses of that 'Dashlet' view that will only process data differently, and draw different graphs. My current code looks something like this:
Dashlet.h
#interface Dashlet : UIView{
#private
UILabel *title;
UIView *controls;
UIView *graph;
}
#property (weak, nonatomic) IBOutlet UILabel *title;
#property (weak, nonatomic) IBOutlet UIView *controls;
#property (weak, nonatomic) IBOutlet UIView *graph;
-(Dashlet*)initWithParams:(NSMutableDictionary *)params;
-(void)someDummyMethod;
#end
And in Dashlet.m
- (id) init {
self = [super init];
//Basic empty init...
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
-(id)initWithParams:(NSMutableDictionary *)params
{
self = [super init];
if (self) {
self = [[[NSBundle mainBundle] loadNibNamed:#"Dashlet" owner:nil options:nil] lastObject];
//some init code
}
return self;
}
Now let's say that I create a subclass called CustomDashlet.h:
#interface CustomDashlet : Dashlet
#property (nonatomic, strong) NSString* test;
-(void)testMethod;
-(void)someDummyMethod;
#end
and CustomDashlet.m
-(id)init{
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
-(id)initWithParams:(NSMutableDictionary *)parameters
{
self = [super initWithParams:parameters];
if (self) {
//do some stuff
}
return self;
}
This, kind of works, but I need to override some of the methods declared in the superclass or even add some of my own. Whenever i try to do something like this in CustomDashlet.m
[self someDummyMethod] or even [self testMethod] I get an exception error like this:
NSInvalidArgumentException', reason: '-[Dashlet testMethod]: unrecognized selector sent to instance
Am I even doing this right? Did I miss something? Am I supposed to make this work in some other way? If anyone has suggestions, please feel free to share your thoughts, thank you for all the help.
The problem is that
SalesDashlet *sales = [[SalesDashlet alloc] initWithParams:nil];
does not return a SalesDashlet instance, as expected, but a Dashlet instance.
Here is what happens:
[SalesDashlet alloc] allocates an instance of SalesDashlet.
The subclass implementation of initWithParams: is called with this instance,
and calls self = [super initWithParams:parameters].
The superclass implementation of initWithParams discards self and
overwrites it with a new instance loaded from the Nib file. This is an instance
of Dashlet.
This new instance is returned.
Therefore SalesDashlet *sales is "only" a Dashlet, and calling any subclass
method on it throws an "unknown selector" exception.
You cannot change the type of objects loaded in the Nib file. You could create a second
Nib file containing a SalesDashlet object. If the main purpose of the subclass is
to add additional methods, then the easiest solution would be to add these methods
in a Category of the Dashlet class.
If the problem is with the
- (Dashlet *)initWithParams:
method it is because the base class declares it with a Dashlet return value, whereas the subclass is redeclaring it with a SalesDashlet return instance.
Always use instancetype as the return type for any init method.
I believe you simply need to change following line in your Dashlet.h file:
-(Dashlet*)initWithParams:(NSMutableDictionary *)params;
to following:
-(id)initWithParams:(NSMutableDictionary *)params;
or better:
-(instancetype)initWithParams:(NSMutableDictionary *)params;
You need to change your init methods.
-(Dashlet*)initWithParams:(NSMutableDictionary *)params
-(SalesDashlet*)initWithParams:(NSMutableDictionary *)parameters
The return type on both of these should be id.
The problem you're running into is similar to trying to do this:
NSMutableArray *someArray = [[NSArray alloc] init];
Despite declaring someArray as an NSMutableArray, you've initialized it as an NSArray, and as such, someArray will actually be an immutable NSArray.
So because your SalesDashlet init method calls its super init method and the super explicitly returns an object of type Dashlet, then the SalesDashlet will also return an object of type Dashlet, so you're trying to call testMethod (a method that only exists in SalesDashlet) on an object of type Dashlet (which doesn't know about the testMethod method).
Changing your return type to id will make the methods return an object of the right type.
As a note, you've done your init, and initWithFrame methods correctly.
SalesDashlet *mySalesDashlet = [[SalesDashlet alloc] initWithFrame:someFrame];
Creating a SalesDashlet in this way will allow you to call [mySalesDashlet testMethod].
Your initWithFrame has return type of id in both super and sub classes.

Custom UIView in Code

Ive created a UIView in code using the addSubview:view method. If I want this to be a custom class rather than the standard UIView, does all this customisation have to take place in the view controllers viewDidLoad method? Seems like there will be alot of code in the viewDidLoad if this is the case! This is the first time ive attempted to create a view in code - the other times ive done it in IB where Ive created a custom class and changed the class of the view in the identity inspector.
Create a new UIView subclass
// MyView.h
#interface MyView : UIView
// public properties, method declarations here
#end
// MyView.m
#implementation MyView
// implementation here, including anything you want to customize this view's
// look or behavior
#end
Then instantiate it in your view controller by importing and referring to the custom class
// ViewController.m
#import "MyView.h"
- (void)viewDidLoad {
[super viewDidLoad];
MyView *myView = [[MyView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:myView];
}

How to create a class with a UIViewController when the subclass of UIViewController is unknown

The title is what I think I need but i will go back one step. I want to create a class which handles certain things in an iOS app. This class might be called by multiple UIViewcontrollers in an iOS app. The class may need to show a UIView at some stage for user input. So my question is how can I show a UIView when I don't know which subclass of UIViewController is calling it? To what can I add the UIView from this class?
I suppose there are two possible answers either the class finds the current UIViewController or the calling subclass of UIViewController passes itself to the class so the class knows.
How is this supposed to be done.
Thanks guys for your help.
I'm going to expand on #ericleaf's comment regarding using a protocol and subclasses. It sounds like you are asking the following:
How can I create a resusable, generic class that presents a view
within a UIViewController subclass?
A great way to do this is to define a protocol in your generic class and have your view controller subclasses support this protocol. The protocol defines an interface for your custom class to comunicate with it's delegate, in this case a UIViewController subclass. Other than the protocol, the objects don't need to know anything else about the implementation of each other.
Any information your custom object needs to be able to present views within it's delegate would be passed via protocol methods. The specifics of the protocol are up to you based on your needs. You could have the custom object "ask" the delegate for information (e.g. what view should I put a subview in?) or you could have the protocol provide information to the delegate and let the delegate deal with it (e.g. here is a subview you can put wherever you want).
There is a lot of great documentation on protocols available on SO and elsewhere. This is long enough already so I kept the example fairly simple.
custom class .h file with protocol definition
// my custom class that adds adds a view to a view controller that supports it's protocol
// forward class definition for the protocol
#class MyAwesomeObject;
#protocol MyAweseomeObjectDelegate <NSObject>
- (UIView *)viewForMyAwesomeObject:(MyAwesomeObject *)awesomeObject;
#end
// this could be defined such that the delegate *must* be a UIViewController. I've left it generic.
#interface MyAwesomeClassObject : NSObject
#property (nonatomic, weak) id <MyAwesomeObjectDelegate> delegate;
#end
custom class .m file
// MyAwesomeObject.m
#import "MyAwesomeObject.h"
#implementation MyAwesomeObject
// this is a dumb example, but shows how to get the view from the delegate
// and add a subview to it
- (void)presentViewInDelegate
{
UIView *containingView = [self.delegate viewForMyAwesomeObject:self];
if (containingView) {
UIView *subview = [[UIView alloc] initWithFrame:containingView.bounds];
subview.backgroundColor = [UIColor redColor];
subview.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
[containingView addSubview:subview];
}
}
MyViewController .h using the custom object
// MyViewController.h
#import "MyAwesomeObject.h"
#interface MyViewController : UIViewController <MyAwesomeObjectDelegate>
#property (nonatomic, strong) MyAwesomeObject *awesomeObject;
#end
MyViewController .m using the custom object
// MyViewController.m
#import "MyViewController.h"
#implementation MyViewController
- (void)init
{
self = [super init];
if (self) {
_awesomeObject = [[MyAwesomeObject alloc] init];
_awesomeObject.delegate = self;
}
return self;
}
// MyAwesomeObjectDelegate
- (UIView *)viewForMyAwesomeObject:(MyAwesomeObject *)awesomeObject
{
return self.view;
}
You can get the class into a string and do a compare.
For example, lets assume your custom UIViewController subclass is CustomViewCon and the UIViewController object reference is myUnknownClassObject, then:
NSString *classString = NSStringFromClass([myUnknownClassObject class]);
Then you can:
if([classString isEqualToString:#"CustomViewCon"]){
//do something like maybe present a particular view
myUnknownClassObject.view = myCustomView; //or anything..
}
Similarly you can check for any class.
Edit: According to the suggestions from comments, you could also do the following(better way):
if([[myUnknownClassObject class] isKindOfClass:[CustomViewCon class]]){
//same as before
}
Why wont you use a block for this?
BaseViewController.h:
#property (copy) void (^addViewBlock)();
- (IBAction)showViewWhenNeeded;
BaseViewController.m:
- (IBAction)showViewWhenNeeded
{
if (self.addViewBlock)
self.addViewBlock();
}
And in your child class, set that block's actions, and call the method when you feel like you should put up a view.
ChildViewController.m
// within some method, propably init or smth
[self setAddViewBlock:^{
[self.vied addSubView:...];
}];
// when need to actually add the view
[self showViewWhenNeeded];

Resources