Recently I was studying the possibility of creating multiple classes in only one file, for this I created a class of UIViewController with a .xib file, the structure of the file is as follows:
MyFristViewController.h
#import <UIKit/UIKit.h>
#interface MyFristViewController : UIViewController
#end
#interface MySecondViewController : UIViewController
#end
MyFristViewController.m
#implementation MyFristViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Frist View Loaded");
}
#end
#implementation MySecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Second View Loaded");
}
#end
My doubt is: How does the system know that is to perform the methods contained in the class called 'MyFristViewController'?
I already tried to modify the custom class in interface builder, tried to change the position of the classes in the file and the system continues running only the existing methods inside the 'MyFristViewController' class why?
How does the system know that is to perform the methods contained in the class called 'MyFristViewController'?
The filenames are irrelevant. When looking at a class, for the most part, the code between #implementation <#ClassName#> and #end is used.
Additional customization of classes can be added through categories and class extensions. These can also be specified in the same file, or different files, because (again) the filenames are irrelevant.
Generally, you should have one class per file to make it easy to read and find your code. See How many classes should a programmer put in one file? for additional discussion.
My doubt is: How does the system know that is to perform the methods contained in the class called 'MyFristViewController'?
Because the methods are in the #implementation block of MyFristViewController.
I already tried to modify the custom class in interface builder, tried to change the position of the classes in the file and the system continues running only the existing methods inside the 'MyFristViewController' class why?
Probably because you've linked them to the methods in first #interface section in your header file. Control-drag to the actual method you want to bind to. It's not clear what problem you're actually seeing.
That said, this is a terrible idea. Put each view controller in its own file. It'll work in one file, but it will create lots of confusion, as you're seeing.
I have worked on projects that define multiple classes in a single file. I loathe this practice. I find it very disorienting and I waste a lot of time searching for where the classes are defined/implemented.
I would advise you not to do this. It ends up being very confusing.
Related
How you guys slim down your view controllers?, sometimes you end up implementing a lot of protocols in your view controller, so there’s a lot of code inside the controller itself. Reading about how to slim down view controllers in iOS I found that a common way is to move DataSources (http://www.objc.io/issue-1/lighter-view-controllers.html) to other class, but what about other delegates?, or if you create views by code?. First, I think about move each delegate to a NSObject class, so I try this:
self.locationManager.delegate = [[FRRYPetDescriptionViewControllerLocationDelegate alloc] init];
Then I ask in IRC and somebody suggest categories, so this is what I got so far:
// FRRYPetDescriptionViewController.h
#interface FRRYPetDescriptionViewController : UIViewController
#property (nonatomic) CLLocationManager *locationManager;
#property (nonatomic) TPKeyboardAvoidingScrollView *scrollView;
#property (nonatomic) UIView *contentView;
#end
// FRRYPetDescriptionViewController+Protocols.h
#interface FRRYPetDescriptionViewController (Protocols) <UITextViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate, UIGestureRecognizerDelegate, MKMapViewDelegate, UIViewControllerTransitioningDelegate, CLLocationManagerDelegate>
#end
// FRRYPetDescriptionViewController+UIAdditions.h
#interface FRRYPetDescriptionViewController (UIAdditions)
- (void)createScrollView;
- (void)createContentView;
#end
// FRRYPetDescriptionViewController+Callbacks.h
#interface FRRYPetDescriptionViewController (Callbacks)
#end
// FRRYPetDescriptionViewController+LocationAdditions.h
#interface FRRYPetDescriptionViewController (LocationAdditions)
#end
This makes me think, what about “private” methods?, do I need to declare all properties in the view controller header file?. What you guys think about this approach or there’s some common pattern to follow to not end with a fat controller?.
Thank you.
The link that you have referred to has beautiful explanation for less bulky controller's programming. But techniques are bit tricky unless you are a seasoned developer. You have asked about multiple techniques in your question. Please check my views on them below: -
Delegates - I personally prefer to keep the delegate code in my controller itself to avoid unwanted confusion specially when you are working with multiple scenarios within the same controller.
Create Views Programmatically - This is the portion where we can cut the large amount of code from UIViewController. Unless it is a single control such as a single label or button, we should make a custom UIView class and let it set all the common properties for view customisation. Controller should only invoke it with necessary parameters.
Properties in Header File - No, concept of data encapsulation says that we should only make those variables public which are required. Rest should move to private domain so that we external objects can't interfere with the class object functionality. So you should declare these properties in class extension (inside .m file). Moreover it is not required to have all variables as properties, when they are private you can declare them as instance variables as property declaration does nothing but to create the getter/setter for that variable.
Private Methods - Same goes to methods as well. If it doesn't have to be exposed to other objects; it should not be in header file. Keep it in extention as private method.
I am using a a library which has quite complicated inherited structure (it consists of a couple of classes, inherited e.g. UITableViewController, UIView, UITableViewCell and others, where some of the classes are used to create custom objects.
I need to add some functionality (to be precise, to implement tap gesture recognizers). The easy solutions is to put a few lines of code into some of the classes of the library.
Generally, I like to have my code separated from libraries code. Is it possible somehow "override" these classes without rewriting them, or to add some extension?
Or the only idea is to write overrides of all the classes generating own classes and tons of useless code?
Or simply add own code to the library?
Additions:
It seems, that categories are right direction, but not particularly, what I want. Here's what I want exactly:
I have a in Class1:
- (void)someMethod {
doThis;
}
And without subclassing // editing the class I would like to transform this to:
- (void)someMethod {
doThis;
andThisToo;
}
Categories add other methods to a class, while I need to add some functionality in already existing method.
You need to use the decorator pattern.
The decorator pattern is used to extend or alter the functionality of
objects at run- time by wrapping them in an object of a decorator
class. This provides a flexible alternative to using inheritance to
modify behaviour.
Since the example you give is pretty sketchy, I can't provide a code example, but check out Wikipedia (http://en.wikipedia.org/wiki/Decorator_pattern)
EDIT
I thought about what you gave and here would be an example of a decorator:
#interface Decorator
#property (strong, nonatomic) id decoratedObject;
- (void)someMethod;
#end
#implementation Decorator
- (void)someMethod {
[self.decoratedObject doThis];
[self andDoThisToo];
}
#end
I like to keep my code clean and I have multiple classes written for custom cells right now. Most of those cells are used in only 1 UITableView.
So lets say we have the classes CustomUITableViewController and CustomUITableViewCell. What I'm looking for is something along these lines in the CustomUITableViewController.
#interface CustomUITableViewController()
//stuff
#end
#interface CustomUITableViewCell : UITableViewCell
//stuff
#end
#implementation CustomUITableViewCell
//stuff
#end
#implemention CustomUITableViewController
-(UITableViewCell*)cellForRowAtIndexPath... {
CustomUITableViewCell *cell = dequeueCellFor...
return cell;
}
-(void)viewDidLoad {
[super viewDidLoad]
//this next line should be right?????
[self.tableView registerNib:nib forCellReuseIdentifier:#"CustomCell"];
}
#end
Is my viewDidLoad method correct? I should write it just like I would if I was writing the UITableViewCell in a separate file?
What do I put in the .xib file? When I try to change the class to a custom class it doesn't link up with CustomUITableViewCell, and of course it doesn't match up with CustomUITableViewController (although I tried anyways.)
Yes.
What do you mean by 'doesn't link up with CustomUITableViewCell'? As long as your nib object is the nib for your custom cell, and in the xib for that cell the root object is a UITableViewCell with its custom class property set to your CustomUITableViewCell type you should be good to go. I've used this approach myself, although I've found that putting logic in the cells is more pain than it's worth.
On a side note, you should be sure to use a three letter prefix with all your classes to avoid collisions with Apple private classes.
The "Not KVC compliant" error is usually caused by one of two things in this situation:
1) You modified the XIBs but Xcode didn't notice the change and so didn't deploy the modified file. This usually occurs when you change something like the cell identifier in the XIB. Delete your app from the simulator/device and try running again.
2) You had properties declared on the custom class for the cell (or possibly something else unrelated in the view hierarchy) that were connected in IB at one time, but you've since changed the class behind IB's back and it doesn't know that it shouldn't try to make those connections again. Right-click each view in the scene to look for any broken connections and remove them. This happens to me if I correct the spelling of a property or change it in any way and don't remove and re-add the connection in IB. 95% of the time, this is the problem when I see that error.
I have a .m file, containing a #implementation ,
but it has gotten too big and I'm trying to move some of the method functions to a 2nd file.
Both .m files begin with
#implementation GesticulatorViewController
#synthesize score_display;
#synthesize game_status;
#synthesize player_options;
#synthesize total_players_field;
#synthesize gesticulation_sentence;
#synthesize gesticulation_input;
#synthesize main_view_manager;
#synthesize game_state;
But I'm getting linker warning:
"ld: duplicate symbol _OBJC_IVAR_$_GesticulatorViewController.gesticulation_input "
You cannot have the same class implementation in two different files.
In your case, you cannot split the implementation of GesticulatorViewController into two .m files.
EDIT:
I would use Objective-C categories to disperse the implementation.
With categories, you have the opportunity to group together methods that perform similar tasks.
Here's an explanation of "Categories and Extensions" from Apple's documentation:
https://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html#//apple_ref/doc/uid/TP30001163-CH20-SW1
I would recommend making more than one controller. Each controller handles a different piece.
I am making a video app. I have a PlayerControlsViewController, it has all the Play and pause buttons within its view.
I have also a Tools controller which has the selection tools and any menu items within it.
The properties for those controllers take that controllers view and remove from super view. then set the view somewhere within its own view and connects it to the PlayerController. which houses the player within it.
Each of these controllers houses its own code to handle its tasks. And sends messages back to the main view controller via a protocol for each.
This will relay commands back and forth between the other controllers, and maintain the setting on the main view controller.
This I believe is the expected standard of operation for the apps to function correctly, and be easily maintainable.
This method also works with Navigation controllers and Tab controllers.
Since they maintain their own code, you can add another view controllers view within your own view.
Just remember to remove it from its superview before adding it to your view.
If it all needs to be in one view, but you think the implementation is too large, you can always do categories :) Just go to File->New->Objective-C Category. Then make the category on your view controller, and add it!
Just remember you cannot add new ivars or properties in the category. You can, however, utilize properties and ivars from your original class.
Also, if you find that you have a LOT of code in your .m view controller files, you might think about looking a little further into the MVC paradigm to split some functionality into other classes. Remember, the view controller should only handle view changes - data manipulation, etc. should be done by other classes :)
Another option would be to copy the source code for some of the methods to another .m file, then #include that file in the main .m file. Put the #include at the point where you cut methods out of the main file.
The trick to making this work is to add the #included source file to your project, but un-check all targets. You don't want Xcode to try to compile the file on it's own - only #include it in your main view controller file.
I have written code for scrolling my table view even when keyboard hides it from entering data, using the notification center and the keyboardDidShow and keyboardDidHide methods.
The problem is that I have almost 8 views in my app where I need to enter some data.
Should I write the whole code in every single .m file, or is there any other easy way I could do it?
You could write some kind of BaseTableViewController which handles all the keyboard notifications.
Then let all the other TableViewControllers inherit from this base controller.
Either you define that method in your application delegate file or create a separate class file which contains the method and you can call it whenever it required.
myMethod.h file
#interface myMethod : NSObject
{
}
- (void) callMyMethod;
myMethod.m file
- (void) callMyMethod
{
// your code
}
In your view, call this method....
myMethod *objMyMethod = [[myMethod alloc] init];
[objMyMethod callMyMethod];
The DRY (Don't Repeat Yourself) principal would lead to creating one set of code to handle the input, not many copies that do the same thing.
The principal of decoupling would lead to a separate class for the code.
A separate class would also allow easier Unit Test to be written.
This sounds like a perfect use-case for a category.