I'm using a 3rd party class that contain the following extention:
#interface BaseClass ()
{
int privateMember;
}
#end
i've created my own subclass:
#interface SubClass : BaseClass {
}
#end
is there a way to access privateMember in SubClass?
EDIT:
actual code
GPUImageMovie.m: (base class)
#interface GPUImageMovie ()
{
BOOL audioEncodingIsFinished, videoEncodingIsFinished;
GPUImageMovieWriter *synchronizedMovieWriter;
CVOpenGLESTextureCacheRef coreVideoTextureCache;
AVAssetReader *reader;
}
MultiTrackGPUImageMovie.h (subclass)
#interface MultiTrackGPUImageMovie : GPUImageMovie {
}
...
#end
MultiTrackGPUImageMovie.m (subclass)
- (void)processMovieFrame:(CMSampleBufferRef)movieSampleBuffer forTarget:(int)targetToSendIdx {
...
CVReturn err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, coreVideoTextureCache, movieFrame, NULL, GL_TEXTURE_2D, GL_RGBA, bufferWidth, bufferHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0, &texture);
...
}
give error
Use of undeclared identifier 'coreVideoTextureCache'
It depends on how the 'private' member has been declared. If there wasn't the #private keyword before it, i. e. it was really
#interface BaseClass ()
{
int privateMember;
}
#end
and not
#interface BaseClass ()
{
#private
int privateMember;
}
#end
then you can easily reference this instance variable simply by using its name - the default access scope for instance variables is protected, i. e. not accessible outside the class, but accessible from subclasses.
However, if it was declared as private, you'll have to fall back using the runtime functions; in your subclass, declare and implement this method:
- (void *)pointerForIvarWithName:(NSString *)name
{
Ivar ivar = class_getInstanceVariable([self class], [name UTF8String]);
return ((char *)self) + ivar_getOffset(ivar);
}
Then use it like this:
int ivarPtr;
ivarPtr = *(int *)[self pointerForIvarWithName:#"privateMember"];
Edit: so it seems the member you're trying to access is in a class extension and not public in the header file. In this case, you can go for the 2nd solution only (although it's not advised to do so).
For me it is impossible to use the default #protected ivar from the class extension in the subclass like said the the accepted answer, when the class extension is in the .m file.
So here is how I could solve this issue without using the runtime API (which should not be used in such a manner).
They are implemented, also for the subclass `SubClass. You can not access them, because the declaration ist not visible to the subclass.
The subclass does not have access to the class extension #interface BaseClass () of the BaseClass.
You have 2 options:
Copy
#interface BaseClass () {
int privateMember;
}
#end
to every subclass. Yes it is the class extension of the BaseClass inside the .m file of the SubClass.
OR
Create a .h file without a .m, only with the class extension code (like above) inside. Import that to the BaseClass and the SubClass.
Related
I have an existing class for which I do not have the source, and I want to
add a property to the class. The private class implements a known protocol which is exposed, but the class type is not exposed.
Some callback happens and I receive the object named answer.
I want to extend the ComplexNumber type to have more properties,
e.g.
#interface NSObject()<ComplexNumber>
#property (assign) BOOL offline;
#end
#implementation SomeClass
didReceiveAnswer:id<ComplexNumber>answer forEquation:(NSString*)equation {
//
if (answer.offline) {
//
}
}
#end
This also fails:
Cast unknown type to be of type NSObject:
if (((NSObject*)answer).offline) {
//
}
There appear to be two issues here:
get access to the private class
add a property to it.
If you know the name of the private class you can simply use it be defining it again:
// SomeClass.h
#interface SomeClass : NSObject <ComplexNumber>
#end
This might seem odd, but this will be sufficient to pass the compilation stage of your build process and allow you to use the property in your code. The existing implementation of the private class will be sufficient to deal with the link stage.
As Daniele Pantaleone points out, the second part is very close to Objective-C: Property / instance variable in category. However I've added it for completness:
// ComplexNumber.h
#protocol ComplexNumber <NSObject>
#property (assign) BOOL offline;
#end
//ComplexNumber.m
#import ObjectiveC;
#implementation NSObject (ComplexNumber)
static void *ComplexNumberKey = &ComplexNumberKey;
-(void)setOffline:(BOOL)offline
{
objc_setAssociatedObject(self, &ComplexNumberKey, #(offline), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(BOOL)offline
{
NSNumber *offline = objc_getAssociatedObject(self, &ComplexNumberKey);
return offline.boolValue;
}
#end
I'm having a hard time understanding private instance variables through example. After reading about private instance variables, I went to Xcode and tried to verify how they work.
In the book I'm reading, it states that if you declare an instance variable in the implementation file of a superclass, the instance variable will be private and inaccessible to subclasses.
I tried proving it doing the following without any luck.
/** SuperClass interface file**/
#import <Foundation/Foundation.h>
#interface ClassA : NSObject
-(void) setX;
-(void) printX;
#end
/**SuperClass implementation file **/
#import "ClassA.h"
#implementation ClassA
{
int x;
}
-(void) setX
{
x = 100;
}
-(void) printX
{
NSLog(#" x is equal to %i", x);
}
#end
/** interface file of subclass **/
#import "ClassA.h"
#interface ClassB : ClassA
#end
/**Main file **/
#import "ClassA.h"
#import "ClassB.h"
int main(int argc, const char * argv[])
{
#autoreleasepool
{
ClassA * a;
a = [[ClassA alloc] init];
ClassB * b;
b = [[ClassB alloc] init];
[b setX];
[b printX];
}
return 0;
}
The program prints the following:
x is equal to 100
isn't "x" a private instance variable and inaccessible by object "b", because "x" is declared in the implementation file of superClass "a" while "b" is a subclass?
The books says "instance variables that are to be accessed directly by a subclass must be declared in the interface section and not in the implementation section...Instance variables declared or synthesized in the implementation section are private instance variables and are not directly accessible by subclasses."
Really confused by this.
The methods setX and printX are public and visible and thus can be called on the instance of ClassB. Since they are public they can also be called by the ClassB, like this.
#implementation ClassB
- (void)fig {
[self setX];
}
#end
What can't be done is for ClassB to directly access the value x. Like this:
#implementation ClassB
- (void)foo {
NSLog(#"x is now %i", x);
}
#end
ClassB does not have direct access to x, but it has indirect access to x through the superclass methods. This indirect access is an object oriented programming concept known as encapsulation.
Ivars have #protected attribute by default, means subclasses can access them. To declare ivar as private, use #private attribute before ivar declaration:
#interface ClassA : NSObject
{
#private
int x;
}
If you declare your ivars in #implementation section, the only way for them to be visible to subclasses is to import .m file in your subclass, but your can't use them because they're private.
Or don't use ivars at all, since Objective-C properties now create ivars automatically. If you need a private property, you can declare it via anonymous category in .m file like this:
#interface MyClass ()
#property (nonatomic) NSInteger x;
#end
UPDATE:
I think I understand what's confusing you. Public and protected ivars are inherited by subclasses and can be accessed directly as instance variables of subclass, no need to use accessor methods from a subclass.
In Objective-C, for instance variables that one doesn't want to put in the header file and, one can put them either in the class extension:
#interface MyClass () {
NSString *myInstanceVariable;
}
// ...
#end
or in the class implementation:
#implementation MyClass {
NSString *myInstanceVariable;
}
// ...
#end
Is there any difference between them?
In the first example you posted, myInstanceVariable is declared in the interface but not explicitly declared as private so it's protected, not private. Protected is the default.
In the second example you posted, myInstanceVariable is declared in the implementation rather than the interface and so it is private.
My preference would be to list it as #private in the interface.
I declare a class extension interface adding vars to it. Is it possible to access those vars in a category of that class?
Sure - any variable is accessible through the runtime, even if it isn't visible in the #interface:
SomeClass.h
#interface SomeClass : NSObject {
int integerIvar;
}
// methods
#end
SomeClass.m
#interface SomeClass() {
id idVar;
}
#end
#implementation SomeClass
// methods
#end
SomeClass+Category.m
#implementation SomeClass(Category)
-(void) doSomething {
// notice that we use KVC here, instead of trying to get the ivar ourselves.
// This has the advantage of auto-boxing the result, at the cost of some performance.
// If you'd like to be able to use regex for the query, you should check out this answer:
// http://stackoverflow.com/a/12047015/427309
static NSString *varName = #"idVar"; // change this to the name of the variable you need
id theIvar = [self valueForKey:varName];
// if you want to set the ivar, then do this:
[self setValue:theIvar forKey:varName];
}
#end
You can also use KVC to get iVars of classes in UIKit or similar, while being easier to use than pure runtime-hacking.
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