I am fairly new to realm of iOS. Coming from Java and Android background i am facing few challenges while learning objective C.
My question: I understand how the above three are different from each other but I fail to understand their use cases in practice.
Do we need a Class Extension for every class with private functions? What is the use of Category, when we can extend a Cocoa/Cocoa-touch class in interface and add custom functions? Please do provide some example from your experience.
Categories are a way to split a single class definition into multiple files.A category can be declared for any class, even if you don't have the original implementation source code.At runtime, there's no difference between a method added by a category and one that is implemented by the original class.
example for categories:
NSString+UrlString.h
#import <UIKit/UIKit.h>
#interface NSString(Additions)
+(void)urlMethod;
#end
NSString+UrlString.m//implmentation
#import "NSString+Additions.h"
#implementation NSString (Additions)
+(void)urlMethod
{
}
#end
The primary interface for a class is used to define the way that other classes are expected to interact with it. In other words, it’s the public interface to the class.
Class extensions are often used to extend the public interface with additional private methods or properties for use within the implementation of the class itself.
Class extensions are used to declare private methods in objective C
For example, to define a property as readonly in the interface, but as readwrite in a class extension declared above the implementation, in order that the internal methods of the class can change the property value directly.
The methods declared by a class extension are implemented in the implementation block for the original class, so you can't, for example, declare a class extension on a framework class, such as a Cocoa or Cocoa Touch class like NSString..
The syntax to declare a extension uses the #interface keyword, just like a standard Objective-C
#interface ClassName ()
#end
you may find that you wish to extend an existing class by adding behavior that is useful only in certain situations. Please refer this
Category is adding methods to a class in the runtime. As far as the runtime is concerned, the methods that are implemented in a class extension, ARE the methods that are available for the class itself. Category in Objective-C is a fancy name for Monkey Patching in other programming languages like C#. You can read about it here.
With that said, you can create a category for UIColor with some method if you want every UIColor to have that behaviour throughout that module. This isn't the case with subclassing. Only the subclassed (theoretically speaking) UIColor object will get those behaviour since there is a distinct difference in the type of the object.
Example:
UIColor has built in methods that give you different colors; you can call UIColor.greenColor() to get the green color; UIColor.blackColor() to get black color and so on...
Suppose you want your own to be called in a similar fashion, you create a category (example in swift) like so
extension UIColor {
static func yourColor() -> UIColor {
return UIColor(red:220/225,green:222/225,blue:223/225)
}
}
This way, it is valid for you to call UIColor.yourColor(). Every UIColor that you would use has this method available. Convenient than subclassing, isn't it?
Creating a subclass has polymorphic implications; categories don't. You subclass only when you need refinement of an existing class and treat it both as a parent and the child when required. As a Java developer you would know when it makes sense to subclass.
An extension is best for private methods which you would like to declare in your .m file. Think of extension as a category private to the .m file.
Class Extesions: If you mean by Extension Methods like in .Net, then it called as Category in Objective-C.
Categories: These are nothing but the Extension Methods, it allows to add methods in existing classes from iOS SDK (like NSString, NSURL, etc.)
For more details: Apple Doc: Category
Primary Interface: Writing a class (Interface in terms of Objective-C) definition inside its implementation file called primary interface.
//ClassName.mm #interface ClassName() {
Declarations;
}
- Methods;
+ Methods;
#end
#implementation ClassName
#end
So, Categories are also one type of primary interfaces.
Related
I am working with a objective-C framework.
I have a public framework header "MyPublicHeader.h" exposed to the client application. I have a custom class in the project,
//MyCustomClass.h file
#interface MyCustomClass.h
- (NSString *) methodA;
#end
//MyCustomClass.m file
#inplementation
- (NSString *) methodA {
}
#end
If I want the client to instantiate the class I have to make it as public framework header. I want to hide the interface as a curiosity, is there any way to do it???
First know that nothing can be truely hidden in Objective-C due to the nature of dynamic dispatch and the features in the runtime which allow discovery of methods etc.
That said there are a number of ways to do this, a couple:
Use a subclass. Declare a superclass and publish its interface as part of your framework. Make your class a subclass of this and publish its interface only within the framework. You define one or more init methods in the superclass which return and instance of the subclass, and if you want to expose any further API define it in the superclass with dummy (or faulting) implementations and less the subclass override etc. This approach is similar to the model used for classes like NSString.
A .h file is just text and you can exploit this: make two .h files, say MyCustomClass.h and InternalMyCustomClass.h. In the first just declare the interface with no members, or the API you wish to make public, and publish that to users of the framework. In the second declare the real interface used within the framework. You must make sure to keep all three of the files (2 .h, .m) in sync. This approach would be call little naughty by some, "here be dragons" by others, or "needs must" by yet others...
You might also like to look into "class extensions" which are related to categories.
Hope that satiates your curiosity a little, and keep up with the curiosity its good (except for cats)!
You could create an empty wrapper class which only holds a reference to your MyCustomClass object.
When they create this object you secretly instantiate an object of your MyCustomClass inside and extract it when they pass you an object of the wrapper class.
Not sure if this is exactly what you want to achieve, but could be a workaround.
Imagine I have define a class MyClass as follows:
The class interface file:
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
#property (nonatomic) NSString *myProperty;
- (void)myPublicMethod;
#end
The class implementation file using categories:
#import "MyClass.h"
#interface MyClass (MyCategory)
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPublicMethod {
NSLog(#"myPublicMethod was called!");
[self myPrivateMethod];
}
- (void)myPrivateMethod {
NSLog(#"myPrivateMethod was called!");
}
#end
An alternative class implementation file NOT using categories:
#import "MyClass.h"
# implementation MyClass
- (void)myPublicMethod {
NSLog(#"myPublicMethod was called!");
[self myPrivateMethod];
}
- (void)myPrivateMethod {
NSLog(#"myPrivateMethod was called!");
}
#end
Was hoping someone could explain the difference between the two implementation file approaches.
Is it the case that using categories means the "private" methods are inherited by any subclasses of MyClass and not using categories means the "private" methods are not inherited by any subclasses?
All methods that exist on a class are always inherited and are callable by anyone regardless of how you declare them. The main difference is whether anybody knows about them. There was also a historic need to declare things before use which leads to internal forward declarations in older and old-style code.
A category is used to add methods to an existing class. A common use is to extend the functionality of one of the existing classes. For example you might implement:
#interface NSURL (HTTPQueryParameters)
- (NSDictionary *)httpQueryParameters;
#end
So from then on you've given NSURL itself the knowledge required to parse HTTP protocol query parameters. It's often the correct factoring to add functionality directly to classes you don't have the source for.
Objective-C used to follow the C rule that methods had knowledge only of those methods that had preceded them within the compilation unit. So to be able to call a method that appeared later in the source file you'd need a forward declaration. If you didn't want to publish that method for the world to see you could achieve that with a category or a class extension (which for this purpose is just an unnamed category).
Nowadays Objective-C methods can call any method that is defined anywhere within the compilation unit, including subsequently in the same source file. It's therefore now normal not to collect up your unpublished methods into a category or an extension just for the benefit of the compiler.
That leaves categories for:
adding functionality to existing classes; and
segmenting your classes if they become very large;
Class extensions are now primarily for:
declaring #propertys without publishing them.
In Objective-C any method call can be sent to any object — objects are dynamically typed. So there's a mapping table in memory at runtime for every class from method name to implementation. The lookup process is to see whether the method is implemented in the class dispatched to. If not then dispatch to the superclass. An exception will be raised if the runtime runs out of superclasses.
The declaration of the method in a category #interface only serves to expose the method to users of the class, including -- as you mentioned in your comment -- subclasses.
(It would be much more usual to use a class extension (sometimes called an "anonymous category") declare a method that you're defining in the main implementation block. Actually, I'm not 100% sure what the interaction is between your category declaration and the main block definition -- I wouldn't have been surprised if it didn't compile, but it does.)
Thus, the only difference between your two examples is that the declaration allows you to create a private header in a situation where you want your own subclasses to access this method, but have framework users who you want to restrict.
Say that Apple has an API defined in a private header file:
// Can't see this at all
#interface NSThing
- (void)secretMethod;
#end
and I have a category:
#interface NSThing (Helpers)
- (void)secretMethod;
#end
Does this override Apple's implementation and will their other private methods start calling into my implementation?
From "Avoid Category Method Name Clashes":
If the name of a method declared in a category is the same as a method
in the original class, or a method in another category on the same
class (or even a superclass), the behavior is undefined as to which
method implementation is used at runtime. This is less likely to be an
issue if you’re using categories with your own classes, but can cause
problems when using categories to add methods to standard Cocoa or
Cocoa Touch classes.
So if you "accidentally" implement a category method with the same name as
an existing method (private or not), the behaviour is undefined.
You should therefore prefix your category methods with a prefix that makes
name clashes unlikely.
This question already has answers here:
Objective-C class extension
(5 answers)
Closed 9 years ago.
What exactly are class extensions and header files? What are the differences? What is the difference between declaring a property/method in a header file vs in a class extension. I am completely new to objective-c so beginner terminology would be beneficial :)
Thanks in advance!
As the name suggests, they extend the class. A class continuation is another name. The class extension is commonly used to declare private methods and properties. You want the class extension to be visible to the #implementation, and not in the header file (i.e. you want the class extension and #implementation to be in MONClass.m).
Types and methods in the header file are generally intended to be public -- available to any client.
Example: The property declared in the class extension will not be visible/accessible to clients who #import the header, but it will be usable by the #implementation because the #implementation can see the declarations of the class extension.
So this can be used to emulate restricted access for your ivars and methods. This is useful because ObjC methods and properties cannot be specified as private/protected/public (e.g. using #public).
Class extensions differ from categories primarily because extensions may declare storage (e.g. properties which will produce backing ivars).
A header file (.h) is where you would declare properties, methods, and protocols publicly in an existing class. You can then import this file and, of course, use it for your implementation.
An extension is another #interface in your implementation (.m) file. This extends the imported header's internal implementation, adding methods that would not be available should someone or something else import the header file associated with the class.
For more information, check out Apple's documentation on customizing existing classes
Q: What exactly are ... header files
A: Header file - is a file, content of which compiler 'inserts' instead of #import... (#include and other similar directives) line. Header files contains public code: forward declarations of classes, enums, variables, functions and other and other.
Q: What exactly are class extensions …
A: Class Extension - is a language construct, which allows you to extends the interface to the class.
To better understand what it is you must understand what is a class category.
Category - is a language construct, which allows you to add functionality (methods only!) to existing class. Even without subclassing.
Example:
You can add new method to NSImage:
#interface NSImage(YourExtensionName)
- (CGImageRef)CGImage;
#end
A Class Extension (also known as a class continuation, or unnamed category) bears some similarity to a category, but it can only be added to a class for which you have the source code at compile time.
In class extension you can use same things you use in a usual #interface block.
Q: What are difference
A: Header file uses for include to your program some ability (structures, data types, constants, functions and so one). Class extensions uses for extends existing class with some functionality. Usually, class extension is a private interface of a class. The functionality declared by a class extension are implemented in the #implementation block for the original class so you can’t, for example, declare a class extension on a framework class, such as a Cocoa or Cocoa Touch class like NSString.
Q: What is the difference between declaring a property/method in a header file vs in a class extension
A: If you declare property/method in header file, then any user of .h file can access to this property/method. Class extensions uses for declare private interface for you class.
I strongly recommend to you read Apple's Objective-C Programming Guide.
I must have misunderstood Categories I made a category on a class to extend it with some methods, and make some methods abstract following the OOP guidelines. But I thought that only when I #import and use the category will those methods in the category be called. Instead I find when I #import and use the base class, that this class will automatically call that method but in the Category on the class, not itself.
What I wanted was if the user tried to use this method in the class without a category a exception would get trowed. And this way I could make different categories on the same class
with slightly different internal behavior.
Am I just misunderstanding Categories ?
Categories add methods to a class without condition or other means of picking and choosing.
Once the methods are added to the class, there is no removal short of mucking with the runtime directly.
Subclasses inherit the additional methods.
It doesn't matter if you #import the method declarations or not.
If you want different versions of a class, declare different subclasses.