I suppose the default scope for ivars is #protected.
I declared a variable like this in the header file of a class:
{
int _test1;
}
But I could print this variable _test1 using NSLog in a totally unrelated object.
NSLog(#"%d", _test1);
Why is _test1 available to the second object?
Where can I find the latest ivars scope rules?
Thanks in advance.
If you are talking objective-c v1, then you are correct... unless otherwise defined (by using the #public, #private, or #packaged keywords), ivars will default to #protected.
You're not showing your code, so I can't be certain, but I wonder if you have the same "issue" as described in this other post: Objective-C - Private vs Protected vs Public
For objective-c 2 this is kind of "deprecated". This article pretty much describes how to do this now: http://robsprogramknowledge.blogspot.com/2011/08/objective-c-property.html
The best place to go for the latest objective-c documentation is probably developer.apple.com... Here's a link to the latest programming manual: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html
Related
I am reading "Effective Objective-C 2.0: 52 Specific Ways to Improve Your iOS and OS X Programs". In "Item 6", the author says that using a pointer on a public ivar is a bad idea, because compiled code will have hardcoded pointer offset, and when new ivar will be added to class, then previously used pointers to some ivars can now point on other variable.
#interface Foo
{
#public
NSString * string;
NSArray * arr;
}
#end
#implementation
...
#end
int main()
{
#autoreleasepool
{
Foo *f=[Foo new];
f->string; //Is it bad idea?
}
return 0;
}
But, aren't ivars and properties dynamic (offset is not known at compile-time)? As Cocoa With Love says:
"All ivars are dynamic in the modern runtime: Since this procedure is followed for all ivars, that means that all ivars in the modern Objective-C runtime are dynamic in that their absolute offsets are never known at compile-time."
If that's true, then why is using a pointer on an ivar bad? Please provide as much low-level detail as possible.
If that's true, then why is using a pointer on an ivar bad? Please
provide as much low-level detail as possible.
Because it breaks encapsulation.
What if class Foo has some custom logic that should be fired when string changes? Or it has to do a calculation? Or Foo wants to make the storage of string unique-ified? Or something else wants to observe changes to said property? Or Foo wants to change the storage semantics later? Or someone wants to subclass Foo and change the behavior there?
Not a problem: "All instance variables in 64-bit Objective-C are non-fragile. That is, existing compiled code that uses a class's ivars will not break when the class or a superclass changes its own ivar layout. In particular, framework classes may add new ivars without breaking subclasses compiled against a previous version of the framework." (https://developer.apple.com/LIBRARY/mac/releasenotes/Cocoa/RN-ObjectiveC/index.html)
This also holds for the 32 bit modern runtime, of course.
Apart from the implementation technicalities, it's an exceptionally bad design though, as bbum notes.
I know this idea completely breaks encapsulation, but say I have the following class extension:
#interface MyClass () {
int reallyImportantIvar;
}
// ...
#end
Normally, the class behaves like it should inside the Objective-C layer - sending and receiving messages, etc. However there is one ('public') subroutine where I need the best possible performance and very low latency, so I would prefer to use a C method. Of course, if I do, I can no longer access reallyImportantIvar, which is the key to my performance-critical task.
It seems I have two options:
Make the instance variable a static variable instead.
Directly access the instance variable through the Objective-C runtime.
My question is: is Option 2 even possible, and if so, what is its overhead? (E.g. Am I still looking at an O(n) algorithm to look up a class's instance variables anyway?)
Actually, if the definition of the C function is within the #implementation block of the class, then it can access private ivars on that class via the usual object->someIvar notation. So while you can use the runtime to access this, I don't think you need to. Just implement the function within the #implementation block of the class in question, and you should be just fine.
Another alternative is to declare the ivar as #package or #public. Then code outside your class's implementation that can #include that class extension can use the ivar.
#public allows any code to do so. #package limits the scope to the same binary as the class's implementation, which is usually appropriate when writing a shared library.
The Objective-C runtime includes the object_getInstanceVariable() function. I believe that's what you're looking for. I haven't checked in detail, but I don't believe there is any big difference between accessing it that way and the normal way.
Before so-called "Modern Objective-C", when creating a new property in category, we needed to implement setter and getter methods. Now, we don't have to do #synthesize; the compiler will automatically create the methods and an instance variable.
But normally, we cannot add instance variables to a category, so what happens if we add a new property in a category with modern Objective-C? Does the compiler create an ivar for us?
You can declare a property in a category, which is equivalent to declaring the getter and (if readwrite) setter selectors.
The compiler will not automatically synthesize the getter and setter methods in your category implementation. If you don't explicitly define them in the category implementation, the compiler will issue a warning. You can use #dynamic in the category implementation to suppress the warning. You cannot use #synthesize in the category implementation; the compiler will issue an error if you try.
The compiler will not add an instance variable for a property declared in a category. You cannot explicitly add instance variables in a category, and you can't trick the compiler into doing it using a property.
I tested my claims using Xcode 4.5.1 targetting iOS 6.0.
Actually I don't know when we were able to add property in categories.
From Apple Docs:
A category allows you to add methods to an existing class—even to one for which you do not have the source.
and
Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main #implementation block for the corresponding class. Using the Clang/LLVM 2.0 compiler, you can also declare properties and instance variables in a class extension.
and this method is used to add storage to an object without modifying the class declaration (in case you couldn't modify or don't have access to source codes of class)
Associative references, available starting in OS X v10.6, simulate the addition of object instance variables to an existing class. Using associative references, you can add storage to an object without modifying the class declaration. This may be useful if you do not have access to the source code for the class, or if for binary-compatibility reasons you cannot alter the layout of the object.
So your question for me seems to be incorrect.
Source: Apple Docs - The Objective-C Programming Language
As others have said, the way to do this is with Associative References. They are implemented much like CALayer's value / key-pair paradigm.. in that basically.. you can "associate" anything, with any "property", or "thing"…
So in your category header… if all you want to do is read a value…
#property (readonly) NSString *uniqueID;
and then write your getter…
- (NSString*) uniqueID { return #"You're not special"; }
But say.. you can't just come up with the value from within your getter.. and you need storage for either an external setter… or the class' own implementation to use… you HAVE to write a setter like...
- (void) setUniqueID:(NSString*)uId
It need not be public, necessarily… but this is where the "magic" happens.
…
[self setAssociatedValue:uId forKey:#"yourInternalStorageName"
policy:OBJC_ASSOCIATION_RETAIN_NONATOMIC];
I realized after looking at this, that I'm using some "personal categories" to help ease the setting and getting etc. of these values.. so I've posted them to this gist, as they are VERY useful.. and include such little gems as…
- (id) associatedValueForKey:(NSString*)key
orSetTo:(id)anObject
policy:(objc_AssociationPolicy) policy;
The secret to "getting it" is the "policy" portion.. These values…
OBJC_ASSOCIATION_ASSIGN = 0,
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
OBJC_ASSOCIATION_RETAIN = 01401,
OBJC_ASSOCIATION_COPY = 01403
capture the same "personality" traits as are expressed when describing your properties in a "normal" declaration. You must tell the compiler how to "store" your values with those same rules, and you'll be good to go.
When using Objective-C properties can you stop creating instance variables altogether or do explicit instance variables (not the ones synthesized by the properties) still serve a purpose where properties would be inappropriate?
can you stop creating instance variables altogether
No, you can't (in a sense). What you can do is stop declaring them if you have properties. If you synthesize a property and you haven't declared the instvar, it will get declared for you, so you are creating an instance variable, just not explicitly.
do they still serve a purpose where properties would be inappropriate?
It used to be the advice to create properties for everything because having synthesized properties does almost all of the retains and releases for you. However, with ARC that reason for using properties to wrap the memory management has gone away. The advice now (for ARC) is, I believe, use properties to declare your external interface, but use direct instance variables where the variable is part of the object's internal state.
That's a good reason to adopt ARC: properties revert to their true purpose only of being part of the class's API and it's no longer necessary to use them as a hacky way to hide memory management work.
Edit
One more thing: you can now declare instance variables in the #implementation so there is now no need to leak any implementation details in the #interface. i.e.
#implementation MyClass
{
NSString* myString;
}
// method definitions
#end
And I'm pretty sure it works in categories too. - see comment below
I recommend declaring everything as properties and avoiding manual ivars altogether. There is no real upside to manually creating ivars. Declare public properties in your header #interface, declare private properties in a private class extension in your .m file.
To some of JeremyP's points, internal use of accessors still has significant value under ARC, even though memory management is no longer a significant concern. It ensures that KVO works properly, subclasses better, supports custom setters (particularly for things like NSTimer), supports custom getters (such as for lazy instantiation), etc. It is exceedingly error-prone to have a mix of accessors and ivars. It's far too easy to forget which you need to access in which way. Consistency is the hallmark of good ObjC.
If you absolutely must declare an ivar for some reason, then you should do it in the #implementation block as JeremyP notes.
UPDATE (Oct-2013):
Apple's guidance (From Programming with Objective-C: Encapsulating Data):
Most Properties Are Backed by Instance Variables
In general, you should use accessor methods or dot syntax for property access even if you’re accessing an object’s properties from within its own implementation, in which case you should use self:
...
The exception to this rule is when writing initialization, deallocation or custom accessor methods, as described later in this section.
This question was addressed before here
When you use synthesize the instance variables are handled and instantiated for you. If you're using Lion with the new version of XCode also take a look at the various properties in ARC in Transitioning to ARC
you can always access properties from outside. So if you want a variable only to be read from inside a class you still have to declare a iVar. Also accessing a public ivar with object->ivar is slightly faster than using a method-call.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Setters and Getters (Noobie) - iPhone SDK
I am a beginner here. I have just started learning iOS for the last two months and I do not have any programming background. (Little bit of Java though). Can anyone please explain what is getter and setter in Objective C? What is the use of them? Why do we use #property and #synthesize?
Getter is a method which gets called every time you access (read value from) a property (declared with #property). Whatever that method returns is considered that property's value:
#property int someNumber;
...
- (int)someNumber {
return 42;
}
...
NSLog("value = %d", anObject.someNumber); // prints "value = 42"
Setter is a method which gets called every time property value is changed.
- (void)setSomeNumber: (int)newValue { // By naming convention, setter for `someValue` should
// be called `setSomeValue`. This is important!
NSLog("someValue has been assigned a new value: %d", newValue);
}
...
anObject.someNumber = 19; // prints "someValue has been assigned a new value: 19"
Usually it doesn't make much sense to just return the same value from getter and print new value in setter. To actually store something you have to declare an instance variable (ivar) in your class:
#interface SomeClass : NSObject {
int _someNumber;
}
and make accessors (the collective name for getters and setters) to store/retrieve it's value:
- (int)someNumber {
return _someNumber;
}
- (void)setSomeNumber:(int)newValue {
_someNumber = newValue;
}
...
SomeClass *anObject = [[SomeClass alloc]init];
anObject.someNumber = 15;
NSLog(#"It's %d", anObject.someNumber); // prints "It's 15"
Okay, now that property behaves just like the usual variable. What's the point in writing all that code?
First, from now on you can add some extra code to the accessors, which will get executed each time the property is accessed or changed. There are multiple reasons for doing that, for example I may want to do some kind of hidden calculations, or updating my object's state, caching stuff etc.
Second, there are cool mechanisms called Key-Value Coding (KVC) and Key-Value Observing (KVO) in Cocoa. They depend on properties. You can read about them in the Developer Library: KVC Programming Guide and KVO Programming Guide. Those are advanced topics though.
Last, in Objective C there is no static allocation for objects. All the objects are dynamically allocated (reason). If you want to keep your object pointers in instance variables (as opposed to properties) you will have to do all the memory management manually every time you assign new value to your ivar (not true when Automatic Reference Counting is on). Using properties you could put some memory management code in the accessors and make your life easier.
I don't believe this explanation will make much sense to someone who is not familiar with Objective C memory management, so, either read some real docs/tutorials on it, or just use properties (instead of instance variables) until you learn all the details one way or another. Personally, I don't like the second option, but it's up to you.
You can use #synthesize to make the compiler generate basic accessors and underlying instance variables for you automatically. Instead of the code above (-(int)someNumber and -(void)setSomeNumber:) you could just write
#synthesize someNumber = _someNumber; // = _someNumbers tells compiler
// to name the instance variable `_someNumber`.
// You could replace it with = `_somethingElse`, of
// course, but that's an ill idea.
This single line generates int _someNumber variable, someNumber getter and setSomeNumber setter for you. If you want the accessors to do anything more complex than just store/retrieve the value from some instance variable, you will have to write them yourself.
Hope all this makes any sense.
"Getters" and "setters" are used to control changes to a variable (field).
A "setter", is most often used in object-oriented programming, in keeping with the principle of encapsulation. According to this principle, member variables of a class are made private to hide and protect them from other code, and can only be modified by a public member function, which takes the desired new value as a parameter, optionally validates it, and modifies the private member variable.
Often a "setter" is accompanied by a "getter" (also known as an accessor), which returns the value of the private member variable.
Getter/Setter methods may also be used in non-object-oriented environments. In this case, a reference to the variable to be modified is passed to the method, along with the new value. In this scenario, the compiler cannot restrict code from bypassing the getter/setter methods and changing the variable directly. The onus falls to the developers to ensure the variable is only modified through the these methods and not modified directly.
In programming languages that support them, properties offer a convenient alternative without giving up the utility of encapsulation.
Property "getters" and "setters" in most any object-oriented language provide an "external" or user interface around private members of instances of your classes. Some OO critics will refer to them as "syntactic sugar," but what it boils down to is that consumers of your classes will use these interfaces that you control programmatically rather than accessing the actual private member(s) themselves. This way, you can (for example) protect a private variable from receiving an invalid or out-of-range value, or make a property read-only by providing only a getter but no setter. Even more interesting is the idea that getters and setters may wrap properties that aren't natively retained in your class, but might (for example) be computed based on other instance members.
Getters and setters surely aren't unique to Objective-C; if you continue programming in other OO languages, you'll find flavors of them in C#, Java, and others.
Good luck.