Where to put const in the class of Objective C - objective-c

If I put a const to the objective C class,
#implementation CLASS_A
const NSString* TAG=#"CLASS_A";
#end
I found const TAG become global variable. And I cannot put two #implementation, each which has a TAG, in one .m file
#implementation CLASS_A
const NSString* TAG=#"CLASS_A";
#end
#implementation CLASS_B
const NSString* TAG=#"CLASS_B"; (Error)
#end
I would like TAG to link to each class with different name. Where will I put the const NSString* TAG=#"CLASS_A" and TAG=#"CLASS_B" in the class?
I also tried this, but got errors.
#implementation CLASS_A
{
const NSString* TAG=#"CLASS_A"; (Error)
}
#end

Create a class method to get the tag externally:
#interface MyClass : NSObject
+ (NSString *)tag;
...
#end
and define it using a static in the implementation file (.m):
#import "MyClass.h"
static NSString * const _tag = #"A tag";
#implementation MyClass
+ (NSString *)tag
{
return _tag;
}
Note: you should implement one class per implementation file.

Related

Objective-C public get set method for private property

I wonder if it is possible to use #synthesize on a private #property so that the get/set methods have public access.
Right now my code looks something like this
SomeClass.h
#import <Foundation/Foundation.h>
#interface SomeClass : NSObject
{
#private
int somePrivateVariable;
}
#end
SomeClass.m
#import "SomeClass.h"
#interface SomeClass ()
#property int somePrivateVariable;
#end
#implementation
#synthesize somePrivateVariable;
#end
Then in some outside function I want to be able to write:
#import "SomeClass.h"
SomeClass *someClass = [[SomeClass alloc] init];
[someClass setSomePrivateVariable:1337]; // set the var
NSLog("value: %i", [someClass getSomePrivateVariable]); // get the var
I know that I can just create my own get/set methods in the header file but I would enjoy using the #synthesize very much more.
If you want a public property to mirror a private one, just override the public property's getter and setter and return the private one.
#interface Test : NSObject
#property NSObject *publicObject;
#end
Then, in the implementation:
#interface Test ()
#property NSObject *privateObject;
#end
#implementation Test
- (NSObject *)publicObject
{
return self.privateObject;
}
- (void)setPublicObject:(NSObject *)publicObject
{
self.privateObject = publicObject;
}
#end

is it possible to have a protected ivar declared in a class extension and have a superclass be able to access it or what to do instead?

I have a class which internally uses an ivar. I don't want to expose the ivar in the public interface of the class (the header) but I declare and use it in the implementation file, like so:
//--------SomeClass.h--------------
#interface SomeClass : NSObject
#end
//--------SomeClass.m--------------
#implementation SomeClass ()
{
#protected
NSMutableDictionary *_privateData;
}
#implementation SomeClass
// ...
#end
Then in a subclass of SomeClass, I try to access _privateData:
//--------SomeSubClass.m--------------
#implementation SomeSubClass
// ...
- (void)someMethod {
NSLog(#"%#", _privateData); // NOPE
NSLog(#"%#", self->_privateData); // NOPE
NSLog(#"%#", super->_privateData); // NOPE
}
// ...
#end
But I can't. Is there a way to do this?
In order to achieve the desired behavior, you should create a subclass header file which declares all of your protected data and #import it in your subclass' .m file.
MammalSubclass.h:
#interface Mammal () {
#protected
NSMutableDictionary *_privateData;
}
//...
#end
Human.m:
#import "Human.h"
#import "MammalSubclass.h"
#implementation Human //subclasses Mammal
- (void)someMethod {
NSLog(#"%#", _privateData);
}
//...
#end

Objective-C Where to define initial Class Properties

just wanted to ask where I define initial class properties?
From other languages I am used to define some standard properties in the head before the content of the class starts.
For example paths to files. Settings and so on.
Where I fill these initial properties with values in Objective-C?
Thanks
Generally it's something like:
MyClass.h:
extern NSString * const staticValue1;
extern NSString * const staticValue2;
#interface MyClass : NSObject
{
NSString *_strval;
int _intval;
float _fltval;
}
#property (retain, nonatomic, readwrite) NSString *strval;
#property (assign, nonatomic, readwrite) int intval;
#property (assign, nonatomic, readwrite) float fltval;
#end
MyClass.m:
NSString * const staticValue1 = #"Something";
NSString * const staticValue2 = #"Something else";
#interface MyClass
#synthesize strval = _strval;
#synthesize intval = _intval;
#synthesize fltval = _fltval;
- (id)init
{
self = [super init];
if (self != nil)
{
[self setStrval:[NSString stringWithFormat:#"This is a %#", #"string"]];
[self setIntval:10];
[self setFltval:123.45f];
}
return self;
}
- (void)dealloc
{
[self setStrval:nil];
[super dealloc];
}
#end
This demonstrates the use of synthesized properties which are being used here to manage the memory of the instance variable _strval, which requires retaining/releasing to avoid memory leaks. Note that [self setStrval] is initialised with an autoreleased object (from [NSString stringWithFormat) and will be retained by the setter method. Alternatively these methods can be called using the following syntax, if you prefer:
self.strval = [NSString stringWithFormat:#"This is a %#", #"string"];
self.intval = 10;
self.fltval = 123.45f;
Maybe some of what you are after can be implemented with class methods.
Class methods are coded with a + (instead of the instance methods' -), and can't refer to instance variables, as they are not associated with any specific instance of the class.
This is a class method to return a default string:
+ (NSString *)myDefaultString
{
return #"Some default value";
}
You call it by simply calling it with the class name at the receiver's place. Imagine you have defined the method in a class called MyClass, the you call it like this:
NSString *str = [MyClass myDefaultString];
You'll notice that there is no alloc/init calls in this.
Public property needs to be define in .h file.
#interface MyClass {
}
#property(nonatomic, reatin) NSString *a;//Define as per needs, then synthesise in .m file
#end
For private property you need define inline category in .m file-
#interface MyClass ()
#property(nonatomic, reatin) NSString *b;//Define as per needs, then synthesise in .m file
#end
#implementation MyClass
#synthesize a = _a;
#synthesize b = _b;
- (void)viewDidLoad {
//You can initialise property here or in init method
self.a = #"Demo1";
self.b = #"Demo2";
}
//Now you can have other code for this class.
#end

Private methods in objective-c not private

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

subclassing issue with static constant variable in iOS

I have Class A and Class B.
Class B subclasses Class A
Class A has a static constant NSString variable
In a method of Class B I need to use the static constant NSString variable of Class A. What are my options ?
I tried declaring the same thing again, but caused problem (internal inconsistency), tried without using (says, variable undeclared).
Any idea how I can solve this problem ?
Thanks.
Make a class method returning that constant, like this:
+(NSString*) constString {
return myConstString;
}
You can declare static constant strings in the .h file. That way they are public and can be used by other classes that import the header file, including your subclass.
Alternatively, you can declare a reference to the string in your Class B using extern:
extern NSString *const MyString;
That basically tells the compiler that the value of that string is defined elsewhere in the code and it doesn't have to worry about it.
By "Class A has a static constant NSString variable", I assume you're referring to having something like the following defined in your Class A .m file:
static NSString * const MyString = #"MyString";
#implementation ClassA
#end
To allow Class A and its subclasses to see the value, you can do something like this:
MDClassAPrivate.h:
#import <Foundation/Foundation.h>
static NSString * const MDBlahBlahKey = #"MDBlahBlah";
MDClassA.h:
#import <Foundation/Foundation.h>
#interface MDClassA : NSObject {
}
#end
MDClassA.m:
#import "MDClassA.h"
#import "MDClassAPrivate.h"
#implementation MDClassA
#end
MDClassB.h:
#import "MDClassA.h"
#interface MDClassB : MDClassA {
}
#end
MDClassB.m:
#import "MDClassB.h"
#import "MDClassAPrivate.h"
#implementation MDClassB
#end
By moving the static const variables to a separate file, you can allow any class to import them in the implementation file.
My personal solution to this problem would be a pseudo-protected method that returns the constant string.
// ClassA.m
#interface ClassA ()
- (NSString *)constantString;
#end
#implementation ClassA
- (NSString *)constantString {
return #"MyConstantString";
}
#end
Then following on into your subclass:
// ClassB.m
#interface ClassA ()
// This is a method redeclaration to avoid build warnings
- (NSString *)constantString;
#end
#implementation ClassB
- (void)someMethod {
NSString *theConstantString = [self constantString];
// do stuff...
}
#end
The assumption here is that your constant string really is constant, if you want it to be dynamic you would need to modify this solution slightly, but it can still handle it.
You can use 'userDefaults' to set a value that is accessible in the whole application.
[[NSUserDefaults standardUserDefaults] setObject:object forKey:#"objectKey"];