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
Related
I have a generator which returns objects conforming to protocol A.
I would like to add a property, probably with categories, to these objects so i can do something to serve my purposes, which obviously isn't there in the protocol.
is this doable?
The more I've thought about this, the more I agree that it's not a duplicate, and in fact the answer is very straightforward as long as what you say you want is what you really want.
Given that you are returning values that conform to some protocol, create a type that conforms to that protocol, and forwards all protocol methods to a wrapped value. Then you can add whatever additional properties you'd like.
For example, given a protocol like:
#protocol Runnable <NSObject>
- (void)run;
#end
You can create a trivial wrapper like:
#interface AnyRunnable: NSObject <Runnable>
- (instancetype)initWithRunnable:(id<Runnable>)runnable;
#end
#interface AnyRunnable (Private)
#property (nonatomic, readwrite) id<Runnable> wrapped;
#end
#implementation AnyRunnable
- (instancetype)initWithRunnable:(id<Runnable>)wrapped
{
self = [super init];
if (self) {
self.wrapped = wrapped;
}
return self;
}
- (void)run {
[self.wrapped run];
}
#end
Now, AnyRunnable is a Runnable, so you can return that from your method. It's also a type you control, so you can add any properties you like to it. This scales to any protocol; you just need to implement the required methods.
It's not possible to do this via a category for the reasons given in Why can't categories have instance variables? (If it were possible to add properties based on protocols, but not classes, then you could just define a protocol that matched your class, and bypass that limitation.)
Here is possible approach (based on Objective-C associated objects). Tested & worked.
Assume we have some class, which we cannot touch
#interface SomeClass: NSObject
#end
#implementation SomeClass
#end
Then some new properties can inject in the following way
#interface SomeClass (VirtualProperty)
#property (atomic) NSInteger virtualProperty;
#property (nonatomic, readonly) NSInteger calculableProperty;
#end
static const char *kVirtualPropertyKey = "virtualProperty";
#implementation SomeClass (VirtualProperty)
#dynamic virtualProperty;
- (NSInteger)calculableProperty {
return self.virtualProperty * 2;
}
- (NSInteger)virtualProperty {
return [(NSNumber *)objc_getAssociatedObject(self,
kVirtualPropertyKey) integerValue];
}
- (void)setVirtualProperty:(NSInteger)newValue {
objc_setAssociatedObject(self, kVirtualPropertyKey,
#(newValue), OBJC_ASSOCIATION_RETAIN);
}
#end
Usage:
SomeClass *some = SomeClass.new;
some.virtualProperty = 5;
NSLog(#"Result: %lu", some.calculableProperty);
Ok, I've read a lot around these days about this topic and I alwyas get confused because the answers is different every search I make.
I need to know the best way to declare instance variables in iOS. So far I know I should only declare them inside .m file and leave .h clean. But I can't do it: the compiler gives me compilation erros.
Here is some code from .m only.
#interface UIDesign ()
// .m file
{
NSString *test2 = #"test2";
}
#property (nonatomic, assign) int privateInt;
#end
#implementation UIDesign
{
NSString *test1 = #"test1";
}
Both strings are declared incorrectly and I don't know why. The compiler says: expected ';' at end of declaration list.
So the question is: how can I declare instance variables? I will only need them inside the class.
You cannot initialize instance variables. They are all initialized to nil or zeroes. So compiler expect a semicolon when you are writing an equal sign.
You can initialize them in init method.
You are attempting to add an instance variable to a class extension or category which is unsupported. [EDIT 2013-05-12 06-11-08: ivars in class extension are supported, but not in categories.] As an alternative:
#interface UIDesign : NSObject
#end
#interface UIDesign ()
#property (nonatomic, assign) int privateInt;
#end
#implementation UIDesign
#synthesize privateInt = _privateInt;
- (void)someMethod {
self.privateInt = 42;
}
#end
On the other hand, if you just want to declare an instance variable inside the implementation, just do it there:
#implementation UIDesign {
int _privateInt;
}
#end
EDIT: just noticed that you're also attempting to initialize instance variables in the declaration which is also unsupported. So:
#interface UIDesign : NSObject
#end
#implementation UIDesign {
NSString *_test;
}
- (id)init {
self = [super init];
if( !self ) return nil;
_test = #"Foo";
return self;
}
#end
Coming from a Java background, I'm having trouble figuring out ways to program defensively in Objective-C.
Assuming SomeClass is mutable and provides a copy method, this is a typical piece of code I'd write in Java:
public MyClass
{
private SomeClass customerList;
...
public SomeClass getCustomerList() {
return this.customerList.copy();
}
public void setCustomerList(SomeClass list) {
this.customerList = list.copy();
}
}
I took me some time to figure out that
#property (nonatomic, copy) SomeClass *customerList;
would make a copy of the setter's argument before assigning it to the customerList property.
What confuses me is writing an appropriate getter. So far it looks like this:
(SomeClass *)customerList {
if(!_customerList) {
_customerList = [[SomeClass alloc] init];
}
return _customerList;
}
which works for all internal method calls like self.customerList = ..., but would pass a direct pointer to any external call creating a security breach. I was considering providing a different public getter that would return a copy, but would like to avoid it as it would need to have an unconventional name. How would you go about this situation?
Thank you.
You can override the -customerList implementation to be: return [_customerList copy];. Be aware that's not usually how others expect accessors to work so make sure to document this.
If you want to return a copy backed by a property and its getter, it's pretty easy to use this form:
#interface MyClass : NSObject
- (SomeClass *)copyCustomerList;
#end
#interface MyClass ()
#property (nonatomic, copy) SomeClass * customerList; // hide what you can
#end
#implementation MyClass
- (SomeClass *)copyCustomerList { return self.customerList.copy; }
#end
although you could implement your own getter instead -- it is unconventional in ObjC, as Carl mentions.
Another approach you could take is to use a different name for the actual property:
#interface MyClass : NSObject
- (SomeClass *)customerList;
#end
#interface MyClass ()
#property (nonatomic, copy) SomeClass * privCustomerList;
#end
#implementation MyClass
- (SomeClass *)customerList
{
// -autorelease if MRC
return self.privCustomerList.copy;
}
#end
I've created two classes with methods with same name. In one of them it is private, in another - public.
Then somewhere on code i write this:
-(void) doMagic:(id) object {
[(ClassA*)object doSmth];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
ClassB * objB = [[ClassB alloc] init];
[self doMagic:objB];
}
In console i see this:
2012-04-25 23:41:28.183 testmagic[558:403] classB - doSmth
Here's classes' sources:
//.h
#interface ClassA : NSObject
-(void) doSmth;
#end
//.m
#implementation ClassA
-(void)doSmth {
NSLog(#"classA - doSmth");
}
#end
//.h
#interface ClassB : NSObject
#end
//.m
#interface ClassB ()
-(void) doSmth;
#end;
#implementation ClassB
- (void)doSmth {
NSLog(#"classB - doSmth");
}
#end
I know, it's because of "message" nature of methods in Obj-C, and at runtime class possibly do not know which of it's methods are private or public, but here's the question:
How can i make really private method? I heard that with decompiling it's possible to see methods names, so someone can just use my private API. How can i prevent it?
The runtime cannot call what it never knows about. The approach I typically take is to use a static function:
MONObject.h
#interface MONObject : NSObject
// ...
#end
MONObject.m
// 'private' methods and ivars are also visible here
#interface MONObject()
// ...
#end
// typically here:
static void fn(MONObject * const self) {
NSLog(#"%#", [self description]);
}
#implementation MONObject
// ...
// sometimes here:
static void fn2(MONObject * const self) {
NSLog(#"%#", [self description]);
}
#end
A workaround to your problem could be to use a proxy/façade class which internally aggregates an instance of your private class. E.g.:
// .h
#interface FoobarFacade: NSObject
- (void)publicMethod;
#end
// .m
#interface FoobarFacade ()
{
Foobar* impl;
}
#end
#interface Foobar: NSObject
- (void)secretMethod;
#end
#implementation Foobar
- (void)secretMethod { NSLog(#"foobar secret method"); }
#end
#implementation FoobarFacade
- (void)publicMethod {
NSLog(#"façade public method");
[impl secretMethod]; // calling into the secret method
}
#end
Of course this isn't 100% safe either, the runtime puts no barriers as others already told.
Right now you can't have truly private methods. When you are declaring a method in a class extension in the .m file you are just hiding it from being exposed in the public header fle. What you are doing now is considered good design because you are hiding the method from the header file which means people would have to go to some length to find those hidden methods, but they can still find them.
Basically the rule I follow is to put as little as I can into the public header as possible and to put everything else into a class extension. This is all you can really do for now.
If you declare the method in the .h file is public. If you want private visibility you have to declare the method in your .m for example:
#interface ClassB (Private_Methods)
- (void)doSmth;
#end
#implementation ClassB
//Rest of .m
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.