Reference properteries declared in a protocol and implemented in the anonymous category? - objective-c

I have the following protocol:
#protocol MyProtocol
#property (nonatomic, retain) NSObject *myProtocolProperty;
-(void) myProtocolMethod;
#end
and I have the following class:
#interface MyClass : NSObject {
}
#end
I have a class extension declared, I have to redeclare my protocol properties here or else I can't implement them with the rest of my class.
#interface()<MyProtocol>
#property (nonatomic, retain) NSObject *myExtensionProperty;
/*
* This redeclaration is required or my #synthesize myProtocolProperty fails
*/
#property (nonatomic, retain) NSObject *myProtocolProperty;
- (void) myExtensionMethod;
#end
#implementation MyClass
#synthesize myProtocolProperty = _myProtocolProperty;
#synthesize myExtensionProperty = _myExtensionProperty;
- (void) myProtocolMethod {
}
- (void) myExtensionMethod {
}
- (void) useMyConsumer {
[[[MyConsumer new] autorelease] consumeMyClassWithMyProtocol:self];
}
#end
MyConsumer will only be called from MyClass, so I don't want any other classes to see that MyClass implements methods on MyProtocol because they aren't public API. Similarly, I don't want MyConsumer to see the class extension within MyClass.
#interface MyConsumer : NSObject {
}
#end
#implementation MyConsumer
- (void) consumeMyClassWithMyProtocol: (MyClass<MyProtocol> *) myClassWithMyProtocol {
myClassWithMyProtocol.myProtocolProperty; // works, yay!
[myClassWithMyProtocol myProtocolMethod]; // works, yay!
myClassWithMyProtocol.myExtensionProperty; // compiler error, yay!
[myClassWithMyProtocol myExtensionMethod]; // compiler warning, yay!
}
#end
Is there any way I can avoid redeclaring the properties in MyProtocol within my class extension in order to implement MyProtocol privately?

What you've been referring to as an "anonymous category" is actually known as a class extension, and is used to declare private functionality in an implementation file. That last part is important, because it means that other classes will not be able to see the declarations that you put into a class extension (and they won't be able to see that your class implements the methods of MyProtocol). This is also probably what is responsible for #synthesize failing without redeclaring the properties.
Instead, declare your conformance to the protocol in the interface of your class, and add whatever methods you want to be public:
#interface MyClass : NSObject <MyProtocol> {
}
// public methods and properties go here
#end
If you add the protocol declaration to your interface, then it also removes the need for your consumer to specify it explicitly. Your consumer method can have the following signature instead:
- (void) consumeMyClassWithMyProtocol: (MyClass *) myClassWithMyProtocol;
EDIT: It sounds like you're looking for a way to selectively expose private functionality. First, I would try to consider a different architecture for what you're trying to accomplish, because what's about to follow is a rather unpleasant solution, and it's generally better OOP if everything is public or private.
With that said, Apple typically solves this problem by having a separate header file for the class in question, which declares the methods that should be visible. So you would have your class interface, in which you expose everything that should be completely public:
// MyClass.h
#interface MyClass : NSObject {
}
#end
And a separate header, in which you declare a category for pseudo-private stuff:
// MyClass+Private.h
#import "MyClass.h"
#interface MyClass (Private) <MyProtocol>
- (void)mySortaPrivateMethod;
#end
MyClass.m would implement everything from those two files, and could still have a class extension:
// MyClass.m
#import "MyClass.h"
#import "MyClass+Private.h"
#interface MyClass ()
- (void)myClassExtensionMethod;
#end
#implementation MyClass
// everything can go here
#end
Then your consumer would include MyClass+Private.h so that it can see the declarations there, and everyone else would simply use MyClass.h.

Related

Why does adding this protocol to this category trigger a compiler warning?

In my code I have the following compiler warning:
Initializing 'MyClass *__strong' with an expression of incompatible type '__strong id<MyProtocol>'
My question is this, why does the compiler warning go away if I remove the protocol from the category?
As in, when when I replace
#interface MyClass (CategoryNameHere) <SomeOtherProtocol>
With
#interface MyClass (CategoryNameHere)
I have found minimal piece of code which reproduces this scenario:
#interface MyWidget ()
#end
#protocol MyProtocol
#end
#protocol SomeOtherProtocol
#end
#interface MyClass <MyProtocol>
#end
#interface MyClass (CategoryNameHere) <SomeOtherProtocol>
#end
#implementation MyWidget
- (MyClass *)sampleMethod:(id<MyProtocol>)v {
MyClass *instance = v;
return instance;
}
#end
The compiler warning is on the line which contains
MyClass *instance = v;
#interface Factory : NSObject #end
#protocol First #end
#protocol Second #end
#protocol Third #end
#interface Base <First, Second> #end
#interface Custom : Base #end
#interface Base (CategoryNameHere) <Second>
#end
#implementation Factory
- (Custom *)sampleMethod:(id<First, Second>)v {
return v;
}
#end
Consider example that you have provided with several renaming.
You can play with it by adding/removing protocols as requirement for Factory's method or by adding/removing protocols as extensions for classes.
The corner stone of this example is bare ( without superclass ) class Base.
It is considered as id<First, Second> by compiler.

Access ivar from subclass in Objective-C

I have class A which has this declaration in it's .m file:
#implementation A {
NSObject *trickyObject;
}
And class B which has this declaration in it's .h file:
#interface B : A
#end
Is there any possibility to access the trickyObject from a method declared in the class B?
If you have a property or method that is private, but you want to make accessible to subclasses, you can put the declaration in a category.
So consider A:
// A.h
#import Foundation;
#interface A : NSObject
// no properties exposed
#end
And
// A.m
#import "A.h"
// private extension to synthesize this property
#interface A ()
#property (nonatomic) NSInteger hiddenValue;
#end
// the implementation might initialize this property
#implementation A
- (id)init {
self = [super init];
if (self) {
_hiddenValue = 42;
}
return self;
}
#end
Then consider this category:
// A+Protected.h
#interface A (Protected)
#property (readonly, nonatomic) NSInteger hiddenValue;
#end
Note, this extension doesn’t synthesize the hiddenValue (the private extension in A does that). But this provides a mechanism for anyone who imports A+Protected.h to have access to this property. Now, in this example, while hiddenValue is really readwrite (as defined in the private extension within A), this category is exposing only the getter. (You obviously could omit readonly if you wanted it to expose both the getter and the setter, but I use this for illustrative purposes.)
Anyway, B can now do things like:
// B.h
#import "A.h"
#interface B : A
- (void)experiment;
// but again, no properties exposed
#end
And
// B.m
#import "B.h"
#import "A+Protected.h"
#implementation B
// but with this category, B now has read access to this `hiddenValue`
- (void)experiment {
NSLog(#"%ld", (long)self.hiddenValue);
}
#end
Now A isn’t exposing hiddenValue, but any code that uses this A (Protected) category (in this case, just B) can now access this property.
And so now you can call B methods that might be using the hiddenValue from A, while never exposing it in the public interfaces.
// ViewController.m
#import "ViewController.h"
#import "B.h"
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
B *b = [[B alloc] init];
[b experiment]; // this calls `B`’s exposed method, and that method is using the property not exposed by `A.h`
}
#end
If you’re interested in a real-world example of this, consider UIKit’s:
#import UIKit.UIGestureRecognizerSubclass;
Generally the state of a UIGestureRecognizer is readonly, but this UIGestureRecognizer (UIGestureRecognizerProtected) category exposes the readwrite accessors for state (to be used, as the name suggests, by gesture recognizer subclasses only).

Expose a private Objective-C method or property to subclasses

According to some official talk, a class in Objective-C should only expose public methods and properties in its header:
#interface MyClass : NSObject
#property (nonatomic, strong) MyPublicObject *publicObject;
- (void)publicMethod;
#end
and private methods/properties should be kept in class extension in .m file:
#interface MyClass()
#property (nonatomic, strong) MyPrivateObject *privateObject;
- (void) privateMethod;
#end
and I don't think there is a protected type for things that are private but accessible from subclasses. I wonder, is there anyway to achieve this, apart from declaring private properties/methods publicly?
One way to solve this is to re-declare the property in your subclass's class extension, and then add an #dynamic statement so that the compiler won't create an overriding implementation of that property. So something like:
#interface SuperClass ()
#property (nonatomic, strong) id someProperty;
#end
....
#interface SubClass ()
#property (nonatomic, strong) id someProperty;
#end
#implementation SubClass
#dynamic someProperty;
#end
This obviously isn't ideal because it duplicates a privately visible declaration. But it is quite convenient and helpful in some situations so I'd say evaluate on a case-by-case basis the dangers involved in this duplication vs. exposing the property in the public interface.
An alternative - that is used by Apple in UIGestureRecognizer - is to declare the property in a separate category header file explicitly named as "private" or "protected" e.g. "SomeClass+Protected.h". That way, other programmers will know they ought not import the file. But, if you don't control the code you're inheriting from, that's not an option.
This is possible by using a class extension (not category) that you include in the implementation files of both the base class and subclasses.
A class extension is defined similar to a category, but without the category name:
#interface MyClass ()
In a class extension, you can declare properties, which will be able to synthesize the backing ivars (XCode > 4.4 automatic synthesis of the ivars also works here).
In the extension class, you can override/refine properties (change readonly to readwrite etc.), and add properties and methods that will be "visible" to the implementation files (but note that the properties and methods aren't really private and can still be called by selector).
Others have proposed using a seperate header file MyClass_protected.h for this, but this can also be done in the main header file using #ifdef like this:
Example:
BaseClass.h
#interface BaseClass : NSObject
// foo is readonly for consumers of the class
#property (nonatomic, readonly) NSString *foo;
#end
#ifdef BaseClass_protected
// this is the class extension, where you define
// the "protected" properties and methods of the class
#interface BaseClass ()
// foo is now readwrite
#property (nonatomic, readwrite) NSString *foo;
// bar is visible to implementation of subclasses
#property (nonatomic, readwrite) int bar;
-(void)baz;
#end
#endif
BaseClass.m
// this will import BaseClass.h
// with BaseClass_protected defined,
// so it will also get the protected class extension
#define BaseClass_protected
#import "BaseClass.h"
#implementation BaseClass
-(void)baz {
self.foo = #"test";
self.bar = 123;
}
#end
ChildClass.h
// this will import BaseClass.h without the class extension
#import "BaseClass.h"
#interface ChildClass : BaseClass
-(void)test;
#end
ChildClass.m
// this will implicitly import BaseClass.h from ChildClass.h,
// with BaseClass_protected defined,
// so it will also get the protected class extension
#define BaseClass_protected
#import "ChildClass.h"
#implementation ChildClass
-(void)test {
self.foo = #"test";
self.bar = 123;
[self baz];
}
#end
When you call #import, it basically copy-pastes the .h file to where you are importing it.
If you have an #ifdef, it will only include the code inside if the #define with that name is set.
In your .h file, you don't set the define so any classes importing this .h wont see the protected class extention.
In the base class and subclass .m file, you use #define before using #import so that the compiler will include the protected class extension.
While the other answers are correct, I'd like to add...
Private, protected and public are available for instance variables as such:
#interface MyClass : NSObject {
#private
int varA;
#protected
int varB;
#public
int varC;
}
#end
Your only choice is to declare it as public in the header file. If you want to at least keep some method separation, you can create a category and have all your protected methods and attributes there, but in the end everything will still be public.
#import "MyClass.h"
#interface MyClass (Protected)
- (void) protectedMethods;
#end
Simply create a .h file with your class extension. Import this into your .m files. Incidentally, this is a great way to test private members without breaking encapsulation (I'm not saying you should test private methods :) ).
// MyClassProtectedMembers.h
#interface MyClass()
#property (nonatomic, strong) MyPrivateObject *privateObject;
- (void) privateMethod;
#end
/////////////////
#import "MyClassProtectedMembers.h"
#implementation MyClass
// implement privateMethod here and any setters or getters with computed values
#end
Here's a gist of the idea: https://gist.github.com/philosopherdog/6461536b99ef73a5c32a
I see good answers for making properties visible, but I don't see exposing the methods addressed very clearly in any of these answers. Here is how I have successfully exposed private methods to the subclass using a Category:
SomeSuperClass.m:
#implementation SomeSuperClass
-(void)somePrivateMethod:(NSString*)someArgument {
...
}
SomeChildClass.h
#interface SomeChildClass : SomeSuperClass
SomeChildClass.m
#interface SomeSuperClass (exposePrivateMethod)
-(void)somePrivateMethod:(NSString*)someArgument;
#end
#implementation SomeChildClass
-(void)doSomething {
[super somePrivateMethod:#"argument"];
}
#end
That's because there's not even a real distinction between private and public. While the compiler may warn you about an interface missing a certain method or instance variable, your program will still work.

how to make a single method in a class to private in Objective-c?

how to make a single method in a class to private in Objective-c?
There's no concept of private methods in Objective-C. What you can do, however, is obmitting the method in the header file and adding a category in a private file.
Usually this is down like this:
#interface MyObject : NSObject {
// ivars
}
// public methods
#end
// usually in a seperate file
#interface MyObject ()
// private methods
#end
An empty name for a category means that it's a class extension, this tells the compiler that the method is required in the main implementation block.
You can't strictly speaking create private methods in Objective-C; but you can create a category in the file containg the implementation (MyClass.m), hiding it from the header file (MyClass.h).
//MyClass.h
#import <Foundation/Foundation.h>
#interface MyClass : NSObject {
}
#end
Implementation file:
//MyClass.m
#interface MyClass ()
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPrivateMethod {
return;
}
#end
Objective-C doesn't support private methods natively by design.
However, you can achieve private method control by using "class extensions" (anonymous categories).
The basic idea is to declare a class extension with your private methods inside the implementation file for your class (not its header), but outside of your #implementation block. You can then implement the methods and no outside class will be able to see them. Like this:
#interface MyClass ()
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPrivateMethod
{
//implementation goes here
}
-(void)someOtherMethod
{
[self myPrivateMethod];
}
#end
Using a class extension forces you to implement the methods in the main #implementation block and requires that they are implemented (much like as if they were declared in the main #interface block in the header).
Unfortunately, due to Objective-C's dynamic nature, this won't actually prevent those methods from being called by other classes. They will get a warning telling them that the class may not respond to the message, but at runtime it will work. The only thing this gives you is the ability to hide the methods from other programmers.
You can't. Only instance variables can be marked as private.
Though there are ways to do something equivalent to private methods.
The general idea is that you don't declare the private method in your header but in your implementation file.
Therefore, if you'd want to have a public (myPublicMethod) and private (myPrivateMethod) method, you're header could look like this:
#interface MyClass {
}
- (void)myPublicMethod;
#end
And then you have three options for your implementation file:
1.
Don't declare the method in any #interface section and just make sure it's implemented before it's being used in the #implementation section.
#implementation MyClass
- (void)myPrivateMethod { }
- (void)myPublicMethod {
[self myPrivateMethod];
}
#end
2.
Use an anonymous category in your implementation file to declare the private methods and implement them in the main #implementation block.
#interface MyClass ()
- (void)myPrivateMethod;
#end
#implementation MyClass
- (void)myPrivateMethod { }
- (void)myPublicMethod {
[self myPrivateMethod];
}
#end
3.
Use a regular category in your implementation file and implement the private methods in a separate #implementation block.
#interface MyClass (PrivateMethods)
- (void)myPrivateMethod;
#end
#implementation MyClass (PrivateMethods)
- (void)myPrivateMethod { }
#end
#implementation MyClass
- (void)myPublicMethod {
[self myPrivateMethod];
}
#end

Hide instance variable from header file in Objective C

I came across a library written in Objective C (I only have the header file and the .a binary).
In the header file, it is like this:
#interface MyClass : MySuperClass
{
//nothing here
}
#property (nonatomic, retain) MyObject anObject;
- (void)someMethod;
How can I achieve the same thing? If I try to declare a property without its corresponding ivar inside the interface's {}, the compiler will give me an error. Ultimately, I want to hide the internal structure of my class inside the .a, and just expose the necessary methods to the header file. How do I declare instance variables inside the .m? Categories don't allow me to add ivar, just methods.
For 64 bit applications and iPhone applications (though not in the simulator), property synthesis is also capable of synthesizing the storage for an instance variable.
I.e. this works:
#interface MyClass : MySuperClass
{
//nothing here
}
#property (nonatomic, retain) MyObject *anObject;
#end
#implementation MyClass
#synthesize anObject;
#end
If you compile for 32 bit Mac OS X or the iPhone Simulator, the compiler will give an error.
You may use of the same idiom used in Cocoa classes. If you have a look to NSString class interface in NSString.h you'll see that there is no instance variable declared. Going deeper in GNUstep source code you'll find the trick.
Consider the following code.
MyClass.h
#interface MyClass : NSObject
// Your methods here
- (void) doSomething;
#end
MyClass.m
#interface MyClassImpl : MyClass {
// Your private and hidden instance variables here
}
#end
#implementation MyClass
+ (id) allocWithZone:(NSZone *)zone
{
return NSAllocateObject([MyClassImpl class], 0, zone);
}
// Your methods here
- (void) doSomething {
// This method is considered as pure virtual and cannot be invoked
[self doesNotRecognizeSelector: _cmd];
}
#end
#implementation MyClassImpl
// Your methods here
- (void) doSomething {
// A real implementation of doSomething
}
#end
As you can see, the trick consist in overloading allocWithZone: in your class. This code is invoked by default alloc provided by NSObject, so you don't have to worry about which allocating method should be used (both are valid). In such allocWithZone:, you may use the Foundation function NSAllocateObject() to allocate memory and initialize isa for a MyClassImpl object instead of MyClass. After that, the user is dealing with a MyClassImpl object transparently.
Of course, the real implementation of your class shall be provided by MyClassImpl. The methods for MyClass shall be implemented in a way that considers a message receiving as an error.
You can use a class extension. A class extension is similar as category but without any name. On the Apple documentation they just define private methods but in fact you can also declare your internal variables.
MyClass.h
#class PublicClass;
// Public interface
#interface MyClass : NSObject
#property (nonatomic, retain) PublicClass *publicVar;
#property (nonatomic, retain) PublicClass *publicVarDiffInternal;
- (void)publicMethod;
#end
MyClass.m
#import "PublicClass.h"
#import "InternalClass.h"
// Private interface
#interface MyClass ( /* class extension */ )
{
#private
// Internal variable only used internally
NSInteger defaultSize;
// Internal variable only used internally as private property
InternalClass *internalVar;
#private
// Internal variable exposed as public property
PublicClass *publicVar;
// Internal variable exposed as public property with an other name
PublicClass *myFooVar;
}
#property (nonatomic, retain) InternalClass *internalVar;
- (void)privateMethod;
#end
// Full implementation of MyClass
#implementation MyClass
#synthesize internalVar;
#synthesize publicVar;
#synthesize publicVarDiffInternal = myFooVar
- (void)privateMethod
{
}
- (void)publicMethod
{
}
- (id)init
{
if ((self = [super init]))
{
defaultSize = 512;
self.internalVar = nil;
self.publicVar = nil;
self.publicVarDiffInternal = nil; // initialize myFooVar
}
return self;
}
#end
You can give MyClass.h to anyone with just your public API and public properties. On MyClass.m you declare your member variable private and public, and your private methods, on your class extension.
Like this it's easy to expose public interfaces and hide detail implementation. I used on my project without any troubles.
According to the documentation I've been looking at there is no problem. All you have to do to hide instance variables is to declare them at the start of the #implementation section, inside { ... }. However, I'm a relative newcomer to Objective C and there's a chance I have misunderstood something - I suspect that the language has changed. I have actually tried this system, using XCode 4.2, building code for the iPad, and it seems to work fine.
One of my sources for this idea is the Apple developer documentation at http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocDefiningClasses.html, which gives this pattern:
#implementation ClassName
{
// Instance variable declarations.
}
// Method definitions.
#end
Two possibilities:
It could be taking advantage of the modern runtime's ability to synthesize instance variables, as bbum suggested.
The property might not have an underlying instance variable in that class. Properties do not necessarily have a one-to-one mapping with instance variables.
No you can't. But you can do this if you're not using #property:
.h
#interface X : Y {
struct X_Impl* impl;
}
-(int)getValue;
#end
.m
struct X_Impl {
int value;
};
...
#implementation X
-(void)getValue {
return impl->value * impl->value;
}
#end
How about a macro trick?
Have tested code below
have tested with dylibs - worked fine
have tested subclassing - Warning! will break, I agree this makes the trick not that useful, but still I think it tells some about how ObjC works...
MyClass.h
#interface MyClass : NSObject {
#ifdef MYCLASS_CONTENT
MYCLASS_CONTENT // Nothing revealed here
#endif
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, assign) int extra;
- (id)initWithString:(NSString*)str;
#end
MyClass.m
// Define the required Class content here before the #import "MyClass.h"
#define MYCLASS_CONTENT \
NSString *_name; \
int _extra; \
int _hiddenThing;
#import "MyClass.h"
#implementation MyClass
#synthesize name=_name;
#synthesize extra=_extra;
- (id)initWithString:(NSString*)str
{
self = [super init];
if (self) {
self.name = str;
self.extra = 17;
_hiddenThing = 19;
}
return self;
}
- (void)dealloc
{
[_name release];
[super dealloc];
}
#end
DON'T do this, but I feel it should be noted that the runtime has the ability to add ivars whenever you want with class_addIvar
I was able to do the following in my library:
myLib.h:
#interface MyClass : SomeSuperClass <SomeProtocol> {
// Nothing in here
}
- (void)someMethods;
#end
myLib.m
#interface MyClass ()
SomeClass *someVars;
#property (nonatomic, retain) SomeClass *someVars;
#end
#implementation MyClass
#synthesize someVar;
- (void)someMethods {
}
#end
The protocol is optional of course. I believe this also makes all your instance variables private though I'm not 100% certain. For me it's just an interface to my static library so it doesn't really matter.
Anyway, I hope this helps you out. To anyone else reading this, do let me know if this is bad in general or has any unforeseen consequences. I'm pretty new to Obj-C myself so I could always use the advice of the experienced.
I don't think the following code written in another answer is working as expected.
The "SomeClass *someVars" defined in the extension class is not an instance variable of MyClass. I think it is a C global variable. If you synthesize someVars, you will get compile error. And self.someVars won't work either.
myLib.h
#interface MyClass : SomeSuperClass <SomeProtocol> {
// Nothing in here
}
- (void)someMethods;
#end
myLib.m
#interface MyClass ()
SomeClass *someVars;
#property (nonatomic, retain) SomeClass *someVars;
#end
#implementation MyClass
#synthesize someVar;
- (void)someMethods {
}
#end