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.
Related
EDIT: edited for clarity
Disclaimer: I'm new and pretty bad. But I have tried very hard and read lots of stuff to figure this out, but I have not...
I think my whole delegate pattern would work, except I can't figure out how to set the delegate property of ViewController to self in the MatchLetter class. The reason is because I can't figure out how to call code there. It's not a view controller, so viewDidLoad or prepareForSegue won't work.
This is what I've got:
ViewController.h
#import <UIKit/UIKit.h>
#class ViewController;
#protocol letterMatchProtocol <NSObject>
- (BOOL) isLetterMatch:(char) firstLetter;
#end
#interface ViewController : UIViewController
#property (nonatomic, weak) id <letterMatchProtocol> delegate;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
char c = 'a';
// This is the method I want to delegate to MatchLetter, to have a BOOL returned
BOOL returnValue = [self.delegate isLetterMatch:c];
}
#end
MatchLetter.h
#import <Foundation/Foundation.h>
#import "ViewController.h"
#interface Delegate : NSObject <letterMatchProtocol>
#end
MatchLetter.m
#import "MatchLetter.h"
#implementation Delegate
// this is the code I think I need to run here, to set the delegate property...
// ViewController *viewController = [ViewController new];
// viewController.delegate = self;
// ... so that isLetterMatch can be run here from ViewController.m
// But I don't know where to put this code, or how to get it to run before the ViewController
// especially since there are no segues or views to load.
- (BOOL) isLetterMatch:(char)firstLetter {
if (firstLetter == 'a') {
return YES;
}
else {
return NO;
}
}
#end
Can somebody please tell me the best way to proceed? Thanks for reading
You asked "Where to set delegate = self? Or should I just use a different design pattern?".
Answer: Don't. An object should never be it's own delegate.
Your code is quite a mess.
Don't name a class "Delegate". A delegate is a design pattern. The whole point of a delegate is that any object that conforms to a particular protocol ("speaks the language") can serve as the delegate. You don't need to know what class of object is serving as the delegate, but only that it speaks the language you need.
An analogy: When you call the operator, you don't care who is working the operator desk. You don't care about his/her gender, religion, ethnic background, how tall they are, etc. You just care that they speak your language.
Likewise, when you set up a delegate, it doesn't matter what type of object gets set as the delegate. All that matters is that the object that is the delegate conforms to the protocol for that delegate.
A table view can have ANY object serve as it's delegate, as long as that object conforms to the UITableViewDelegate protocol. You usually make you view controller be the table view's delegate, but you don't have to. You could create a custom class that manages your table views, and have it be the delegate. There is no "TableViewDelegate" object class. There is instead a UITableViewDelegate protocol, and any object that conforms to the protocol can act as a table view's delegate.
Edit: Your question is confusing. I think what you're proposing is that your Delegate class would create a view controller and make itself the delegate for the view controller.
If that's what you are talking about, your thinking is backwards. The view controller is using the Delegate class as a helper class. Any given instance of a view controller class can create an instance of the Delegate class and set it as it's delegate if it desires. You might have 3 instances of ViewController at one time, each with it's own instance of your Delegate class.
Thus, the ViewController object is the one that should create and set up an instance of Delegate if it needs one:
- (void) viewDidLoad;
{
self.delegate = [[Delegate alloc] init];
//other setup here
}
I'm trying to call an instance method which is in my UIViewController from within a UIView. In my UIViewController I have something like:
-(void) test {
NSLog(#"test");
}
In my UIViewController, I create an instance of my UIView like so:
draggableView = [[DraggableView alloc]initWithFrame:CGRectMake(20, 190, 280, 280)];
In my draggableView, I then want to call the test instance method. How do I do this without creating a new instance of the UIViewController?
I have tried this, but it doesn't seem like a very elegant solution and I get an error "No visible #interface ..."
View does not have default method to access its view-controller object.
You need to pass the view-controller object into the view object yourself.
Typical way to do this is making a property.
#class ViewController;
#interface DraggableView : NSObject
#property (readwrite,nonatomic,assign) ViewController* theOwnerViewController;
#end
#implementation DraggableView
- (void)testCallingOwnerViewControllerMethod
{
[self.theOwnerViewController test];
}
#end
You need to set the theOwnerViewController after you created the DraggableView object.
- (void)loadView
{
draggableView = [[DraggableView alloc]initWithFrame:CGRectMake(20, 190, 280, 280)];
draggableView.theOwnerViewController = self;
//...extra view setup.
}
Use assign to avoid retain-cycle on the property.
Delegate pattern
You can do this by above pattern, but as you noticed, you need to know and forward-declare the owner view-controller class' name from its view (which is sub-node of the VC). Usually This is bad design choice because it's easily makes circular dependency (or backward dependency), which usually creates tight-coupling.
Instead, you can use delegate pattern to avoid circular dependency issue.
#protocol TestDelegate
- (void)test;
#end
#interface DraggableView : NSObject
#property(readwrite,nonatomic,assign) id<TestDelegate> testDelegate;
#end
#implementation DraggableView
- (void)test
{
[self.testDelegate test];
}
#end
You need to set the testDelegate after you created the DraggableView object.
#interface ViewController<TestDelegate>
#end
#implementation
- (void)test
{
// do something.
}
- (void)loadView
{
draggableView = [[DraggableView alloc]initWithFrame:CGRectMake(20, 190, 280, 280)];
draggableView.testDelegate = self;
//...extra view setup.
}
#end
In this case, you don't have to know the class name of the view object before you create. Any class which conforms TestDelegate protocol can be used, and now the view and VC are loosely-coupled via the protocol.
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];
I have implemented a subclass of ECSlidingViewController.
InitialViewController.h
#interface InitialViewController : ECSlidingViewController
#property (nonatomic, strong) WebViewController *webVC;
#property (nonatomic, strong) MenuViewController *menuVC;
#end
I need access to the .webVC from the .menuVC, but am unable to access them from self.parentViewController.webVC getting the error:
"UIViewController does not have a member named webVC"
but when I check in the debugger
po self: <MenuViewController>
po self.parentViewController: <InitialViewController>
po self.parentViewController.webVC: error: property 'webVC' not found on object of type 'UIViewController *'
However, when I navigate the object tree of self in the local variable window, I can go
-self <MenuViewController> 0x0000001
-UITableViewController
-UIViewController
-_parentViewController <InitialViewController>
-webVC <WebViewController
-menuVC <MenuViewController> 0x0000001
Where self and self.parentViewController.menuVC have the same memory address
When I navigate down and right-click->print Description, I get
Printing description of self->_parentViewController->menuVC:
<MenuViewController: 0x8e8c720>
Those '->' and the '_' make me think I'm seriously missing something involving pointers and ivars.
I'm also interested if there is a better way to implement this functionality. This kind of smells like I'm breaking MVC with a child Controller knowing about itself and its parent. However, selections on the menu directly manipulate the webView I have loaded.
Answer:
UIViewController does not have this property built in so you need to cast it:
[(InitialViewController*)self.parentViewController webVC]
Explanation:
This is a question of Classes and SubClasses. Say I have a class MyView which is a subclass of UIView. This class has a couple methods on it, -(void)method1; and -(void)method2;. The .h would look something like this:
#interface MyView : UIView
- (void)method1;
- (void)method2;
#end
I then create a MyView* named thisView and assign it to my ViewController's view property:
#import "MyView.h"
- (void)viewDidLoad
{
MyView* thisView = [[MyView alloc] init];
[self setView: thisView];
}
The UIViewController class's property, view is declared like this:
#property (...) UIView* view;
Pay extra special attention to the UIView* there.
Because view is declared as a UIView*, it will accept values that are subclasses of UIView*, but when I access it later, it will give me a MyView in a box labeled UIView.
In other words, consider this code:
- (void)viewDidLoad
{
MyView* thisView = [[MyView alloc] init];
[self setView: thisView];
UIView* returnedView = thisView; //This is perfectly fine
}
UIViewController will return something along the lines of returnedView, which is a MyView in a UIView container.
When your program goes to access the view, all it knows is that has received something in a box labeled "UIView", so it only knows that it can run methods on it that are present in the UIView class. We have to explicitly tell it "No, this is a MyView," and we do that with casting:
[self.view method1]; //This will break
[(MyView*)self.view method1]; //This will work
Back to your problem
When you access self.parentViewController, you are given a InitialViewController in a UIViewController box, so you have to explicitly tell your program that it is an InitialViewController. You do that by casting:
InitialViewController* parentVC = (InitialViewController*)self.parentViewController;
[parentVC.webVC doSomething];
Warning:
Your VC that is accessing webVC must have a declaration of (InitialViewController*), so you'll need to watch out for forward declaration errors.
If you are unfamiliar with this, it is when Class A imports Class B, but Class B also imports Class A:
A
--->Import B
B
--->Import A
Which results in
A
--->Import B
------->Import A
----------->Import B
and so on.
A class cannot import itself.
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];