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.
Related
This question isn't about bridging headers and all that. I've got all that working. My question is specifically about what I need to do to my Swift classes to get them to show up in Obj-C code.
Take, for example, this simple class:
class MyClass {
var value: String = ""
}
If I have this class in my Project, it doesn't get included in the MyProject-Swift.h file that gets auto-generated. My understanding is that in order to use a Swift class in Objective-C, my class needs to derive from a class that Objective-C knows about. This is where I start to doubt the actual requirements.
If my class were derived from a UIViewController, then no problem. But if this is just a model object, then it's not deriving from anything. While it is entirely possible to easily make my class derive from NSObject, and thus, it gets properly imported into the Obj-C code, deriving from NSObject can cause other issues down the road.
So if I don't want to make my class derive from NSObject, what can I do to make it visible to my Obj-C files? Is there a doc I just couldn't find that explains how to do this?
As far as I am aware currently, Only Swift classes that inherit from NSObject can be declared #objc and bridged into an Objective-C project.
Without that conformance/inheritance, you'll end up missing some crucial functionality to Objective-C like message sending.
All of that being said, an Objective-C class has to inherit from a parent class and the default root class is NSObject. You almost definitely want to just inherit and make your class a PONSO.
I want to extend my class which I wrote in Swift. I want to write the extension in Objective C because I need to put some Objective C code which I can't port into Swift. I know that I can create a .h and .m and then include the .h at the bridging header. But in the .h, I need to include the original .swift class file right?
How can I solve this? Can I include using myclass-swift.h? Thanks.
The following documentation may be helpful: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-ID122. You've probably already looked at that, but just in case. The following question may also help: Extending a Swift class with Objective C category.
As you know, to use Objective-C code in Swift there is the bridging header. To go the other way around, there is the auto-generated *-Swift.h header that should be imported in .m (and .mm) implementation files. The documentation says it should not be imported into .h files. In fact, the compiler won't let you import it into a .h file that is included, directly or indirectly, in the bridging header. However, with some care you can import it into other .h files.
Now, suppose your Swift class is called SwiftClass and you want to add to it a method called ocFunction() implemented in Objective-C. One approach, essentially presented in the aforementioned answer, is to implement a category in an Objective-C source file (.m):
#implementation SwiftClass (OCExtension)
-(void)ocFunction {...}
#end
Then modify your SwiftClass to include the following:
class SwiftClass : NSObject
{
...
#nonobjc func ocFunction()
{
self.perform(Selector(("ocFunction")))
}
...
}
The referenced answer suggests doing this in an extension, but since you have full control of the SwiftClass source, you can just do it in the class directly. BTW, the Objective-C category function could be named something other than the SwiftClass's function, thus eliminating the need for #nonobjc.
Another approach might be to define an Objective-C wrapper interface like this:
#interface SwiftClassOC : NSObject
+(void)ocFunction:(SwiftClass*)sc;
#end
and make it available to Swift via the bridging header. The implementation would go into a .m file. Then your ocFunction() in SwiftClass would look like
func ocFunction()
{
SwiftClassOC.ocFunction(self)
}
Please note that SwiftClassOC is stateless, so it's essentially a set of helper functions that take a SwiftClass pointer. SwiftClass is the one maintaining the state.
You can extend an Objective-C class with Swift, but you cannot extend a Swift class with Objective-C.
I want to write the extension in Objective C because I need to put some Objective C code which I can't port into Swift
You can do that, but not as part of the Swift class. What I usually do is make a "helper" class in Objective-C and import it into Swift.
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.
Which one is the best practice-
I have 10 different types of protocol, which is conformed by 10 different class object (),
classA conform to protocolA
classB conform to protocolB
...
...
You may consider them one-to-one relation rather than shared protocol by 2 different class.
Now should i group all these 10 protocols in a header file named Protocol.h and then import that header file when any class want to conform his protocol. Like in class A -
#import Protocol.h
Or should i place each protocol in the header file of the class which contain object that conform particular protocol,like- object_name<protocol> . Like Class X contain object of ClassA which conform to ProtocolA.
#protocol ProtocolaA <NSObject>
#interface ClassX:
{
id <ProtocolA> objectA;
}
Thanks for your reply.
There's no right or wrong answer to this. My personal preference is generally one protocol per header. However, if there are two or more protocols that go logically go together and will usually be imported together, you might put them in the same header file.
If your protocols form an API for a framework, that is another reason to put them together so classes that use the framework API can just do one import.
But I would recommend not using a generic name like protocol.h, try to think up something more descriptive of what the protocols are actually for e.g. all the protocols and class interfaces for Cocoa are logically imported (nested imports are used) in one header called Cocoa.h.
On the second part, I find it generally better to keep protocols and class interfaces in separate headers.
I would not put all protocols in one header, as each protocol is only needed by one class. Importing the protocol header would give you all protocols.
What Apple is doing in these cases is:
1) Include the protocol in the header of the class where the protocol is used (for example UITableView.h and UITextView.h):
#class ClassX;
#protocol ProtocolX<NSObject>
// Use ClassX here
#end
#interface ClassX
#property (nonatomic) id <ProtocolX> myProtocol;
#end
2) Another solution seen in Apple's header is to have an own file for both the header and the implementation (for example CLLocationManager.h and CLLocationManagerDelegate.h).
Bottom line: I would prefer both these solutions to putting all protocols in one header.
You may place protocol in the header file of the class which contain object that conform particular protocol or add protocal as new file.
Working with Protocols
I'm learning some Objective-C, specifically iOS-related stuff. Whenever I generate a new UIViewController, or UITableViewController, etc, both the generated .h and .m files contain an #interface. The application will continue to compile if I delete the #interface from the .m file, also. What is the purpose of this #interface in the .m file?
The #interface in the .m file is a class extension (a category with no name). It's now in the templates to let you put any declaration of internal methods or ivars you don't want to expose to other parts of the code.
With the advent of the modern Objective-C runtime and the progress of clang, a well written class should:
1) have only public methods in the header
2) have ivars and internal methods declared in the internal class extension
Technically, it is a "class extension" (see ("Extensions" section of) the Objective-C intro docs). In practice, it has become common to use this as a "private" interface (it is only "visible" to the file in which it exists). Objective-C does not stop anyone else from calling these methods, but they won't "see" them (think of the .h file as your public interface and this anonymous category as your private interface).
It is handy for declaring #propertys which you don't want to expose publicly.