Putting methods in separate files - objective-c

I have a class (MyClass) with a lot of methods. Consequently, the .m file has become quite difficult to read. I'm relatively new to Objective-C (having come from REALbasic) and I was wondering if it's possible to put some of the methods in MyClass into different files and then include them in the class. How would I go about this in Xcode?

Yes it is possible and fortunately this can be done easily in Objective-C with Categories.
Say you have your base class MyClass.
#interface MyClass : NSObject
-(void) methodA;
#end
And the according implementation file (not relevant here).
Then you can create a category by defining a new interface in a new header file:
// the category name is in parenthesis, can be anything but must be unique
#interface MyClass (extended)
-(void) methodB;
#end
and the implementation file:
#implementation MyClass (extended)
-(void) methodB {
}
#end
Common convention to name these files is ClassToAddMethodsTo+CatgoryName, i.e.:
MyClass+extended.h
MyClass+extended.m
Group related functionality into categories and give it a meaningful name.

In Objective-c you can break a class into 'categories' - a class spread across many files. The normal Object-Oriented way is to use SuperClasses and SubClasses.
This is almost certainly a code smell telling you that you have a design problem. See this antipattern

There is one thing you could do..........
But be warned, some might consider this pure blasphemy. :)
Say you have a class with two methods you want to have in separate files.
You'll have three files:
• Class.h
• Class.m
• Class_otherMethod.m
Your Class.h should look just like any other. I think it's better to keep the header file complete, but this 'trick' can work on separating .h files just as well.
#interface Class : NSObject
- (void) method;
- (void) otherMethod;
#end
In your Class.m file you will #include the Class_otherMethod.m inside the Class #implementation like this:
#import "Class.h"
#implementation Class
- (void) method {
// do something.
}
#include "Class_otherMethod.m"
#end
And your Class_otherMethod.m file will have only the bare otherMethod implementation:
- (void) otherMethod {
// do something different.
}
Why this works
It's quite simple actually. The preprocessor simply "pastes" the content of Class_otherMethod.m inside the Class.m file and the compiler treats it as one big long file. :P

Related

Objective C - Categories and Inheritance - Add method to base and add override to derived class

I know that categories should not be used to override a method in the class they are extending. However, what about the following scenario.
Consider the classes:
Base.h
#import <Foundation/NSObject.h>
#interface Base: NSObject { NSNumber *n; }
#end
Derived.h
#import "Base.h"
#interface Derived: Base { NSString *s; }
#end
With categories:
Base+Serialize.h
#import "Base.h"
#interface Base (Serialize)
- (NSString*)serialize;
#end
Base+Serialize.m
#import "Base+Serialize.h"
#implementation Base (Serialize)
- (NSString*)serialize
{
return [NSString stringWithFormat:#"%#", n];
}
#end
Derived+Serialize.h
#import "Derived.h"
#import "Base+Serialize.h"
#interface Derived (Serialize)
- (NSString*)serialize;
#end
Derived+Serialize.m
#import "Derived+Serialize.h"
#implementation Derived (Serialize)
- (NSString*)serialize
{
return [NSString stringWithFormat:#"%#, %#", s, [super serialize]];
}
#end
Obviously, this is a contrived/simplified example. But it works well to demonstrate what I would like to do. Essentially, I want to provide additional functionality to multiple classes in an inheritance hierarchy.
Is this a safe/valid use of categories? Any gotchas?
This is an acceptable way to use categories. Categories do actually add the message to the class, so the message will work just like any other message. This includes inheritance.
Perhaps one thing to watch out for is that you can run into name collisions. I don't know how the runtime handles them, but if two categories supply the same message you may have unexpected behavior since the message you expect is not being called. That being said, you may just want a name which is a little more distinctive than serialize, unless of course, you need that name (e.g. you have an informal protocol).
This doesn't seem like a very good object model. Base.h and Derived.h seem fine. What about making a Protocol to define the serialize: method, rather than a category? That would be a little cleaner. Base.h would indicate that it would implement the protocol and Derived could override the method as needed.

Hiding types from Objective-C framework header files

I'm writing a media player framework for a project I'm working on. This depends on VLC. One of my classes' header file looks like this
#import <vlc/vlc.h>
#interface MediaPlayerVLC : MediaPlayer
{
libvlc_media_player_t *player;
libvlc_media_t *media;
}
#end
I need the instance variables in the class, and I need the #import <vlc/vlc.h>, because they're defined in there. But I don't want users of this framework to have to import all of VLC's headers just for these two types. I've seen a few solutions to this problem around...
Forward declaration, such as #class. Unfortunately, these types are typedef struct types, I can't seem to find any way to forward declare them
declare the ivars as void *, then cast them whenever I want to use them. I'd like to avoid this if possible, as we lose type-safety and implementation files become full of ugly casts.
I've seen this in Apple's frameworks...
#interface CAAnimation : NSObject <NSCoding, NSCopying, CAMediaTiming, CAAction>
{
#private
void *_attr;
uint32_t _flags;
}
What does _attr point to? I guess it would be a struct of ivars, I'm curious what advantages this has...
Two header files for the class, one public and one private. The private one would look like the above, and the public would just have void * pointers. This is pretty ugly, as I'd have to be very careful to keep them both in sync.
What's considered best practise? Is there an approach I've missed?
You can use class extensions. You should try doing this:
MediaPlayerVLC.h:
#interface MediaPlayerVLC : MediaPlayer
{
}
#end
MediaPlayerVLC.m:
#import "MediaPlayerVLC.h"
#import <vlc/vlc.h>
#interface MediaPlayerVLC ()
{
libvlc_media_player_t *player;
libvlc_media_t *media;
}
#end
#implementation MediaPlayerVLC
// The implementation
#end
From Apple's docs:
Class extensions are like anonymous categories, except that the
methods they declare must be implemented in the main #implementation
block for the corresponding class.
Using the Clang/LLVM 2.0 compiler,
you can also declare properties and instance variables in a class
extension.
That's using a class extension category to declare extra ivars in the implementation file.
With the newest compiler you can also declare ivars in your class's #implementation section:
// MediaPlayerVLC.m
#import "MediaPlayerVLC.h"
#import <vlc/vlc.h>
#implementation MediaPlayerVLC
{
libvlc_media_player_t *player;
libvlc_media_t *media;
}
...
#end
You can put ivars in implementation like
#implementation Something
{
int a;
}

Inherited Methods that are not in Header File of Superclass

Is there a way to have "private" methods in a superclass (which are not in its header file) and still be able to access these from subclasses?
You could use a custom category, for example:
Stuffy.h
// The "official" header file to be used by almost anyone
#interface Stuffy {
int myMember;
}
- (void) somePublicMethod;
#end
Stuffy+Secret.h
// The magic header file, which should only be used by knowledgable people
#import "Stuffy.h"
#interface Stuffy (Secret)
- (void) _pseudoProtectedMethod;
#end
Stuffy.m
#import "Stuffy+Secret.h"
#implementation Stuffy
- (void) somePublicMethod {
// ...
}
#end
#implementation Stuffy (Secret)
- (void) _pseudoProtectedMethod {
// ...
}
#end
Subclasses of Stuffy can now either import Stuffy.h in their .m files and stick to the public API, or import Stuffy+Secret.h and use the semi-protected stuff.
Note, that Objective-C has no true notion of protected or private methods. Basically, anyone can include Stuffy+Secret.h and use the stuff declared there.
You can "cheat" several ways. In addition to categories, you can simply cast your Stuffy pointer to FunnyStuff, and have a whole 'nother #interface for it. (Just don't declare any statics and don't do an #implementation.) Or, a little cleaner, cast to an #protocol that defines your added methods. (And, since you're doing a subclass, you can simply add the protocol to your subclass definition, and avoid any casting.)
Keep in mind that Objective-C doesn't require that every method in an #implementation have a corresponding declaration in #interface, and method calls are entirely dynamic, effectively including name look-up. The only thing you have to do is to trick the compiler into allowing the call. (In fact, you can make the call with no declaration at all if you don't mind the compiler warning.)

Adding .m source code files for room for long or extra routines

My Xcode .m source files are getting long due to numerous routines, some of which are rather long. I'm looking for the way to add additional .m files and then call the routines in them from my main .m file. I understand the mechanics of adding source files, I really want to know how to call routines in source files other than the one I am currently in.
Example:
mySource.h contains
-(void) myRoutine01;
-(void) myRoutine02; ...
-(void) myRoutine99;
Inside mySource.m I call a routine thusly:
[self myRoutine01];
[self myRoutine02];
[self myRoutine03];
I'd like to keep mySource.m manageable in length such that I am doing mostly logic stuff with calls to routines that are actually housed in other source files. Some routines can get very long and housing them in their own .m files would be most convenient.
How do I call routines in another source file? Do I just replace "self" with something?
What you are calling "routines" are actually methods.
You can organize your methods using Objective-C categories, placed in multiple files.
A category is a way to add methods to existing Objective-C classes. Read the documentation to learn more about this.
This way, you can organize your source files and keep them small, by grouping specific methods into a specific category.
For instance:
MyClass.h
#interface MyClass: NSObject
{}
- ( void )someMethod;
#end
MyClass+Misc.h (category)
#import "MyClass.h"
#interface MyClass( Misc )
- ( void )someOtherMethod;
#end
MyClass.m
#import "MyClass.h"
#import "MyClass+Misc.h"
#implementation MyClass
- ( void )someMethod
{}
#end
MyClass+Misc.m
#import "MyClass+Misc.h"
#implementation MyClass( Misc )
- ( void )someOtherMethod
{}
#end

Beginner's Objective-C Syntax Question

I came across the following code snippets from Apple's Documentation.
The Interface is fairly straightforward:
#import <Foundation/Foundation.h>
#import "ApplicationCell.h"
#interface CompositeSubviewBasedApplicationCell : ApplicationCell {
UIView *cellContentView;
}
#end
The implementation:
#import "CompositeSubviewBasedApplicationCell.h"
#interface CompositeSubviewBasedApplicationCellContentView : UIView {
ApplicationCell *_cell;
BOOL _highlighted;
}
#end
#implementation CompositeSubviewBasedApplicationCellContentView
//not important, abbreviated...
#end
I can't quite figure out why there is another #interface declaration in the implementation file. I assume that it is a way of declaring private instance variable. Am I right?
And since the interface already said that CompositeSubviewBasedApplicationCell extends ApplicationCell, what does CompositeSubviewBasedApplicationCellContentView : UIView mean?
Thanks in advance.
It's the definition of another class. In most cases, this would be in a separate file, but it's also possible to define multiple classes in one file, especially if they're closely related.
CompositeSubviewBasedApplicationCellContentView is probably not used by any classes except for CompositeSubviewBasedApplicationCell, so it doesn't need to have its own header file.
CompositeSubviewBasedApplicationCell and CompositeSubviewBasedApplicationCellContentView are two different classes.
I can't quite figure out why there is another #interface declaration in the implementation file. I assume that it is a way of declaring private instance variable. Am I right?
Yes, that's a way to make a class completely private. If someone wanted it to be partially private they could just extend it in the implementation file like this:
#interface CompositeSubviewBasedApplicationCell()
#end