How to access public instance variable in Objective-C? - ios

I am having following condition:
#interface MyClass:NSObject
#public NSString *str;
#end
#implementation
-(id)init{
}
#end
Now I want to access str variable outside MyClass in Other Class, (1) Using MyClass Object (2) without using MyClass Object, How can I achieve that?

You can call using this:
MyClass *a;
a.str;
Without the object, you cannot call an instance variable. However, you can call static method with this declaration:
#interface MyClass:NSObject
+ (void)doX;
#end
#implementation
+ (void)doX {
// do whatever
}
then in another class you just need to call:
[MyClass doX];
However, let a public instance variable is not a good practice. The reason is that it will let any class, methods change that instance variable without your control. For example, they can set the NSString *str to nil and then nobody can call anything, or they may forget to do memory management when they call.
A better practice for public variable is using #property
For example, your string should be declared like:
#property (nonatomic, retain) NSString * str;
and then in the implementation:
#implementation MyClass
#synthesize str;
The good thing about property is that compiler will generate gettter and setter methods for you and those setters will handle memory correctly for you.
More about properties here

Sigh, i realise this post is LONG dead but I believe The above answer is incorrect.
well the first bit.
Please see the link below.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-SW1
for the above interface to work, you NEED to declare a property for use outside of its class
Because the instance variable it is not visible outside its class.
well; You don't NEED to. Doing something like MyClass->str is valid.
Please see this example
#interface Foo : NSObject {
#public NSInteger publicMember;
#private NSInteger aproperty;
}
#property (assign) NSInteger aproperty;`
then the calling class
Foo *f = [Foo new];
f.aproperty = 90;
//f.publicMember = 100; property 'publicMember' not found of type Foo *
f->publicMember = 100;
But as the above post said, you should always use #properties because if var public was a string, you are not retaining the string in any way.

Related

Exposing for unit testing in objective c

Let's say I have a class:
#interface MyClass
#end
#implementation MyClass {
myType *_myIvar;
}
#end
And I'd like to expose it for testing. I see two ways to do this:
expose the ivar as a property:
#interface MyClass
// Pragma mark - Expose for testing
#property myIvar;
#end
#implementation MyClass
#end
Use key value coding:
-(void)myTest {
myType *myIvar = [myClass valueForKey:#"_myIvar"];
}
Which method is preferred?
First - you don't test private methods or state of a class for unit-testing, as per TDD best practices.
Having that said, however, sometimes it's the only way to observer possible side-effects. I personally always wrap any ivar of a class with a property. For data which is not supposed to appear in the public interface I put it in the extension inside of the implementation file:
// Implementation file
#interface TDWClass ()
#property (strong, nullable) NSString *tdw_p_message;
#end
P.S. This also helps to maintain certain semantic for the given property (you immediately can see not just storage modifier, but other attributes the property is supposed to follow: like, being read-only, nullability, etc..)
When it comes to testing such a property, this approach helps to conveniently read any "private" property (or accessing a private method) by re-declaring it in a category:
// XCTest file
#interface TDWClass (XCTest)
#property (strong, nullable) NSString *tdw_p_message;
#end

Objective-C variable that is accessible in other classes

I have a NSString object called language and I want to access it from other classes what is the proper way? I tried following steps:
1) I created delegate method and send string via delegate
-(void)setLanguageForController:(NSString *)language {
self.language = language;
}
Console showed this
unrecognized selector sent to instance delegate
2) I created method getCurrentLanguage
static NSString *language;
+(NSString*)getCurrentLanguage {
return language;
}
And access like this
NSString *myLanguage = [[MyView alloc] getCurrentLanguage];
you should declare language as a property in your class .h file.
#property (nonatomic, copy) NSString* language;
When you want to set language:
initalize your class instance: yourObj
call: yourObj.language = "whatever"
or [yourObj setLanguage:"whatever"];
Each property declaration ends with a type specification and a name.
For example:
#property(copy) NSString *title;
This syntax is equivalent to declaring the following accessor methods:
- (NSString *)title;
- (void)setTitle:(NSString *)newTitle;
read more about objective-C property here
You don't need to create your method like setLanguageForController and getCurrentLanguage to get and set the your variable like this if you want to access it from other class. You need to create a property in your interface file or .h file, it will be public and it provide its getter and setter method which you can access from any class by the instance variable of your class that contains your property.
You can declare your property in .h or class interface file like this:
#property (nonatomic, strong) NSString* language;
To set it's value you can use.
obj.language = #"value"; or [obj setLanguage:#"value"];
To get its value. You need to use same instance variable like this
NSString *strLanguageValue = obj.language;

Difference when declare variable

I have a class below:
#interface Person : NSObject {
NSString *_firstname;
}
#property NSString *firstName;
#end
#implementation Person
#synthesize firstname;
#end
This will declare three variables: firstname, self.firstname and _firstname
What is the difference between the three variables and how do you using with each case?
In modern Objective-C you don't need to create instance variable if you already synthesizing properties.
From what you write it appears that you are confusing properties and ivar.
Properties create getters and setters to your ivars, but they are not ivars, they are methods that access you ivars to set or get their values.
Your class can be sum up like that:
#interface Person : NSObject
#property NSString *firstName;
#end
#implementation Person
#end
At compile time this will ensure that you can access your ivar using methods and name your ivar as _firstName.
Dot notation create access to properties so self.firstName (using ARC and default property option -nonatomic,strong-)calls that method
- (NSString*)firstName
{
return _firstName;
}
While calling self.firstName = #"foo"; calls:
- (void) setFirstName:(NSString*)name
{
if (_firstName == name) {
return;
}
_firstName = name;
}
Underlining implementation could be a little different.
The first one NSString *_firstname; is an instance variable. The #property is a property which is syntesized (you don't have to manually synthesize properties in modern Objective-C). When you declare a property you can access its instance variable with _propertyName or with self.propertyName.
It is up to you whether you declare your variables as instance variables or as properties but it is more common and suggested to declare them as properties (using properties you can have access to getters and setters, which means that you can run code before the value of the property will be set or will be read).
You can chain instance with property using
#interface Person : NSObject {
NSString *_firstname;
}
#property NSString *firstName;
#end
#implementation Person
#synthesize firstName = _firstname;
#end
Both pointers are pointing same instance now.

Creating properties only visible to subclass in Objective-C

I am attempting to create an abstract class and inherit some of its properties in a subclass. If I leave the properties in the abstract class' header file, all of the properties are accessible. The problem is that the instance of the subclass can also access those properties, which is not always desirable in my case.
For instance, I have a delegate in my abstract class that sends down button presses to its sub class. I realize that this may not be the best way of structuring inheritance, so other suggestions are welcome. However, I would still like to know how my subclass can inherit some properties from its superclass without making all of those properties available in its instance. Thanks in advance!
Here is some example code below:
#interface AbstractClass : UIView
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
…
#protocol ButtonDelegate
#required
- (void) buttonWasPressed;
#end
…
#interface SubClass() <ButtonDelegate>
- (id)init {
self = [super init];
if (self) {
self.buttonDelegate = self;
}
return self;
}
-(void) buttonWasPressed {
[self doSomething];
}
…
#implementation ViewController
- (void)viewDidLoad {
SubClass *subClass = [[SubClass alloc] init];
subClass.buttonDelegate = self; // THIS IS NOT DESIRABLE
}
Do like UIGestureRecognizer does.
All public properties and methods goes into UIGestureRecognizer.h
All protected properties and methods goes into UIGestureRecognizerSubclass.h.
Only import this in the *.m-files. Never include it in any public header.
All private properties and methods goes into *.m-files. Use the #interface ClassName ()
Example https://gist.github.com/hfossli/8041396
how to my subclass can inherit some properties from its superclass
without making all of those properties available in its instance
What is the problem with this?
#import <Foundation/Foundation.h>
#interface Animal : NSObject
{
#protected
NSString *name; // default access. Only visible to subclasses.
}
#end
#implementation Animal
-(NSString*)description {
return name;
}
#end
#interface Cow : Animal
#end
#implementation Cow
-(id)init {
self=[super init];
if (self){
name = #"cow";
}
return self;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
Cow *cow = [Cow new];
NSLog(#"%#", cow); // prints the name through internal access
// error accessing from the outside: NSLog(#"%#", cow.name);
Animal *animal = [Animal new];
// error accessing from the outside: NSLog(#"%#", animal.name);
}
}
Maybe I misunderstood the question, you say
Creating properties only visible to subclass in Objective-C
and then
The problem is that the instance of the subclass can also access those
properties
Which one is it?
Create an empty category on top of your implementation file (.m):
#interface AbstractClass()
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
In that way, your subclass will inherit and can access that property, but not other external classes because it's not in the header.
I don't think there is any way to achieve this using property declaration.
Either a property be visible for all (declared in .h file) or it will be invisible for all (declared in .m file using category)
I guess one way is declaring public/protected variable in .h file class declaration:
#interface AbstractClass : UIView {
...
id<ButtonDelegate>buttonDelegate;
...
}
#end
I am not sure about this, but give a try.
I see one approach that can fit your problem, however, it is pretty rude. Use Antonio's suggestion and create the private category with the property. As you've mentioned, it's scope is limited to the .m file. So you can put your subclasses into that file. This will be hard to read the code if subclasses are huge, but this is the only way for you as far as I understand.
EDIT: well, I have another solution. Copy
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
to all your subclasses. This will give you a warning about the absence of the property's #synthesize, but should work. I'd prefer this, if subclasses wont be changed or added often.
Let me describe how it would work.
We add a property into the Abstract class, and it is hidden for all (even for subclasses):
// .m file
#interface Abstract ()
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
#implementation Abstract
#synthsize buttonDelegate;
#end;
But due to runtime features of Objective-C we still can call for that property, and there will not be any runtime error, only compiler warning.
To get rid of that warning and to add an ability to autocomplete, we add property without #synthsize into all subclasses:
#interface MySubclass : Abstract
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
This will tell the compiler that there is such a property somewhere. There will be also one warning about the absence of #synthesize, but Xcode will still could autocomplete if you write something like
MySubclass *subclass = ...
subclass.butto...
It can not be done. There is no private or protected in objective-c. Stuff declared in the .m file "private" interface is only visible to that class and not in any subclass. Also you can always use your "private" properties/methods from outside if you want, although it would be bad practice to do so.

Proper way to use instance variables/property/synthetize with ARC [duplicate]

This question already has answers here:
Declaration/definition of variables locations in ObjectiveC?
(4 answers)
Closed 9 years ago.
What is the proper way to work with instance variables (declared on interface), their #property and #synthesize, when working in ARC project? What I now do is following:
SomeClass.h:
#interface SomeClass : NSObject {
NSString *someString;
}
#property(nonatomic, copy) NSString* someString;
and SomeClass.m:
#implementation SomeClass
#synthesize someString;
- (void)someMethod {
self.someString = #"Foobar";
}
The thing is that there are other approaches that works, like using just the #property:
SomeClass.h:
#interface SomeClass : NSObject
#property(nonatomic, copy) NSString* someString;
Accessing the someString without self:
SomeClass.m:
#implementation SomeClass
#synthesize someString;
- (void)someMethod {
someString = #"Foobar";
}
etc. I'm new to Objective-c, I'm used to Java. What is the proper way to work with attributes then? I understand that special cases will have special behavior, but what is the best approach in general? (by general I mean I want to access the variable from the class itself and from "outside" and I want ARC to still work correctly, eg. I don't have to worry about memory leaks)
For simple properties, you don't need the instance variable declaration or the #synthesize. The clang compiler will generate both for you by default. So you could write this in the header:
#interface SomeClass : NSObject
#property (nonatomic, copy) NSString *someString;
#end
And the implementation:
#implementation SomeClass
- (void)someMethod {
self.someString = #"Foobar";
}
#end
Avoid direct instance variable access unless you are in the -init method or overriding the setter. Everywhere else you should use the dot syntax (self.someString). If you do need access to the instance variable, the default synthesize will create an underscore-prefixed ivar, e.g. _someString.
Note that for classes with mutable versions like NSString/NSMutableString and NSArray/NSMutableArray the standard practice is to use a copy property. If you use strong on a string or array, the caller might pass in a mutable version and then mutate it from under you, causing hard-to-find bugs.
Check out this SO post for information about ARC.
(Edited) The "strong" attribute tells ARC to keep an object around until the object with the property is deallocated. You do need the "copy" attribute because an NSString property could have been passed in as an NSMutableString. The "copy" guarantees that the original object will be kept around. Again, I apologize for the incorrect/misleading information I originally had here.
The reason you can access the instance variable someString as well as the property self.someString is that the #synthesize someString line creates an instance variable for the property and creates methods for getting and setting the value of it. However, it is recommended that you use the property instead of directly using the instance variable because by using the instance variable, you cannot let the parent object know that you've changed one of its properties.

Resources