In Objective-C, is there any way to run a specific selector automatically every time an object is instantiated? (I know about +initialize but I need an instance method).
Specifically, I am writing a custom string class (that inherits from my own root class with a similar interface to NSObject) and I am trying to make it 'play nicely' with Objective-C constant strings. To do this, I have the following class definition (as required by the runtime):
// 1) Required Layout
#interface MYConstantString : MYObject {
//Class isa; inherited from MYObject
char *c_string;
unsigned int length;
}
Now, I want to implement my string class by using a pointer to a C-struct inside the class (this "C object" is already well implemented so I basically just want to wrap it in an Objective-C class). Ideally therefore, my Objective-C class would look like this:
// 2) Desired Laout
#interface MYConstantString : MYObject {
// Class isa;
StringObject *string;
}
And then the class and instance methods would just wrap C function calls using that StringObject.
So because I can't have the desired ivar layout (2), I wish to hack around the required ivar layout (1) to work for me. For example:
- (void)fixup {
// Pseudocode
temp = copystring(c_string);
c_string = (void *)StringObjectNewWithString(temp); // Fudge pointer
length = ... // I can do something else with this.
}
So, to return to the question, is there a way to call -fixup automatically, rather than having to do the following every time I make write an Objective-C constant string?
MYConstantString *str = #"Constant string";
[str fixup];
I know this is an obscene hack, and Objective-C constant string interoperability isn't totally crucial for what I need, but it would be nice to be able to use the #"" syntax and make the code more 'naturally' Objective-C.
I'm guessing you left out an important fact: you're using -fconstant-string-class=MYConstantString when building to have the compiler use your class for constant string objects (#"...").
Given that, then, no. There are two significant problems. First, "instance creation" for constant strings happens at compile time, not run time. The reason that there's a required layout is that the compiler does nothing but lay out the string's data in a data section with a reference to the appropriate class object where the isa pointer goes. It doesn't invoke any custom code. It is not necessarily even aware of such custom code at compile time. A given translation unit may not include the constant string class. The reference to that is resolved at link time.
Second, the constant string instance is almost certainly laid out in a read-only data section. There's a good chance that even calling your -fixup method manually as in your question would encounter an access violation because you'd be modifying read-only memory.
You should consider using a class cluster. Make MYConstantString one concrete subclass of an abstract base class. Make it conform to the required layout and just use the character pointer and length ivars as they are. If it would be convenient to translate to StringObject at various points, do that at those points. Implement other, separate concrete subclasses to use StringObject internally, if desired.
MYConstantString *str = #"Constant string";
That can't work because #"..." is an NSString, and it's not only a problem of layout but of instance sizes. If you want 0-copy or anything like that, what you have to do is have something like:
MYConstantString *str = [MyConstantString stringWithNSString:#"Constant string"];
and let -stringWithNSString: recognize when the passed string is a constant one (I'm pretty sure the concrete class of constant strings is easy to recognize, and probably hasn't changed ever for backward compatibility reasons) and then hack it around to grab the pointer to the bytes and similar things.
Let us say that application has a concept of cars in it. A car is an instance of Car. There are a small number of possible cars and most, but not all of the data about a car is known at design time. Each kind of car is a singleton; there is at most one of each kind of Car per app.*
Since they are singletons, and since they are named, that suggests some sugar. The most important piece of sugar is this: when I import "Car.h", into a file, I want the symbols "MAFerrari", "MAMercedes", and "MAMclauren" to start showing up in my autocomplete where ever code completion thinks I am trying to provide an instance of a Car*.
My next greedy desire is that I want to be able to send instance methods to my MAFerrari literal, e.g. [MAFerrari topSpeed] means "get the singleton instance of Car that corresponds to the Ferrari and send topSpeed to it", but I acknowledge the utter triviality of this. Even pragmatists should know what their Utopia looks like.
Finally, if possible, I want clean way to declare the constant properties of the three cars as literal data at the top of my Car.m file.
Now, again, I don't actually expect all of that to be possible in Objective C. I just want to know how close we can get to that all that.
The closest idea I've had is to subclass Car for each type of car and provide a +sharedInstance method for each one. sharedInstance can implement the singleton pattern: if it's initialized, return it, otherwise initialize it, store it (where? it should be private to the Car class hierarchy), then return it. Each subclass can implement its own initializer which contains the defaults for that subclass.
Here's what I don't like about this:
I think I have to import all the header files whenever I work with these subclasses. This absolutely sucks. Is there another way?
I have to create .m/.h file pair for every one of these subclasses. That seems like a lot of boilerplate, since they have no unique behavior.
[[MAFerrari sharedInstance] topSpeed] isn't quite as good as [MAFerrari topSpeed], but I acknowledge that this is trivial.
Anyway, how would you do it?
*In reality, it's not cars, but in-app purchase assets, for the curious.
It sounds like what you want is just a global variable. You can create a global variable named whatever you want (say, MAFerrari) and stick whatever you want in it — whether the contents of the variables are instances of multiple singleton classes or multiple instances of the same class doesn't really matter from the point of view of having global names to refer to the objects.
Easy-peasy.
Note that these aren't singletons; they're just long-lived instances of a class stored in global variables.
// Bolt.h
#import <Foundation/Foundation.h>
#interface Bolt : NSObject
// Properties
- (instancetype)initWithLength:(NSUInteger)length
diameter:(NSUInteger)diam
thread:(NSUInteger)thread
grade:(NSUInteger)grade;
// etc.
#end
extern Bolt * twentyFiveByTwelveCoarseThreadGradeEightBolt;
extern Bolt * fiftyByTenFineThreadGradeFiveBolt;
//
// Bolt.m
#import "Bolt.h"
Bolt * twentyFiveByTwelveCoarseThreadClassEightBolt;
Bolt * fiftyByTenFineThreadGradeFiveBolt;
// This will be run before main() but after classes are loaded
__attribute__((constructor))
static void initialize_global_Bolts(void)
{
twentyFiveByTwelveCoarseThreadClassEightBolt = [[Bolt alloc] initWithLength:25
diameter:12
thread:175
grade:8];
fiftyByTenFineThreadGradeFiveBolt = [[Bolt alloc] initWithLength:50
diameter:10
thread:1
grade:5];
}
#implementation Bolt
- (instancetype)initWithLength:(NSUInteger)length
diameter:(NSUInteger)diam
thread:(NSUInteger)thread
grade:(NSUInteger)grade
{
// Do initialization
}
#end
Now you can do things like [fiftyByTenFineThreadGradeFiveBolt maximumTorque]; wherever Bolt.h is imported.
You can't put dictionary or other literals at top level, because they resolve into method calls, which can't be used outside of other methods.
I usually see this question asked the other way, such as Must every ivar be a property? (and I like bbum's answer to this Q).
I use properties almost exclusively in my code. Every so often, however, I work with a contractor who has been developing on iOS for a long time and is a traditional game programmer. He writes code that declares almost no properties whatsoever and leans on ivars. I assume he does this because 1.) he's used to it since properties didn't always exist until Objective C 2.0 (Oct '07) and 2.) for the minimal performance gain of not going through a getter / setter.
While he writes code that doesn't leak, I'd still prefer him to use properties over ivars. We talked about it and he more or less sees not reason to use properties since we weren't using KVO and he's experienced with taking care of the memory issues.
My question is more... Why would you ever want to use an ivar period - experienced or not. Is there really that great of a performance difference that using an ivar would be justified?
Also as a point of clarification, I override setters and getters as needed and use the ivar that correlates with that property inside of the getter / setter. However, outside of a getter / setter or init, I always use the self.myProperty syntax.
Edit 1
I appreciate all of the good responses. One that I'd like to address that seems incorrect is that with an ivar you get encapsulation where with a property you don't. Just define the property in a class continuation. This will hide the property from outsiders. You can also declare the property readonly in the interface and redefine it as readwrite in the implementation like:
// readonly for outsiders
#property (nonatomic, copy, readonly) NSString * name;
and have in the class continuation:
// readwrite within this file
#property (nonatomic, copy) NSString * name;
To have it completely "private" only declare it in the class continuation.
Encapsulation
If the ivar is private, the other parts of the program can't get at it as easily. With a declared property, the clever people can access and mutate quite easily via the accessors.
Performance
Yes, this can make a difference in some cases. Some programs have constraints where they can not use any objc messaging in certain parts of the program (think realtime). In other cases, you may want to access it directly for speed. In other cases, it's because objc messaging acts as an optimization firewall. Finally, it can reduce your reference count operations and minimize peak memory usage (if done correctly).
Nontrivial Types
Example: If you have a C++ type, direct access is just the better approach sometimes. The type may not be copyable, or it may not be trivial to copy.
Multithreading
Many of your ivars are codependent. You must ensure your data integrity in multithreaded context. Thus, you may favor direct access to multiple members in critical sections. If you stick with accessors for codependent data, your locks must typically be reentrant and you will often end up making many more acquisitions (significantly more at times).
Program Correctness
Since the subclasses can override any method, you may eventually see there is a semantic difference between writing to the interface versus managing your state appropriately. Direct access for program correctness is especially common in partially constructed states -- in your initializers and in dealloc, it's best to use direct access. You may also find this common in the implementations of an accessor, a convenience constructor, copy, mutableCopy, and archiving/serialization implementations.
It's also more frequent as one moves from the everything has a public readwrite accessor mindset to one which hides its implementation details/data well. Sometimes you need to correctly step around side effects a subclass' override may introduce in order to do the right thing.
Binary Size
Declaring everything readwrite by default usually results in many accessor methods you never need, when you consider your program's execution for a moment. So it will add some fat to your program and load times as well.
Minimizes Complexity
In some cases, it's just completely unnecessary to add+type+maintain all that extra scaffolding for a simple variable such as a private bool that is written in one method and read in another.
That's not at all to say using properties or accessors is bad - each has important benefits and restrictions. Like many OO languages and approaches to design, you should also favor accessors with appropriate visibility in ObjC. There will be times you need to deviate. For that reason, I think it's often best to restrict direct accesses to the implementation which declares the ivar (e.g. declare it #private).
re Edit 1:
Most of us have memorized how to call a hidden accessor dynamically (as long as we know the name…). Meanwhile, most of us have not memorized how to properly access ivars which aren't visible (beyond KVC). The class continuation helps, but it does introduce vulnerabilities.
This workaround's obvious:
if ([obj respondsToSelector:(#selector(setName:)])
[(id)obj setName:#"Al Paca"];
Now try it with an ivar only, and without KVC.
For me it is usually performance. Accessing an ivar of an object is as fast as accessing a struct member in C using a pointer to memory containing such a struct. In fact, Objective-C objects are basically C structs located in dynamically allocated memory. This is usually as fast as your code can get, not even hand optimized assembly code can be any faster than that.
Accessing an ivar through a getter/setting involves an Objective-C method call, which is much slower (at least 3-4 times) than a "normal" C function call and even a normal C function call would already be multiple times slower than accessing a struct member. Depending on the attributes of your property, the setter/getter implementation generated by the compiler may involve another C function call to the functions objc_getProperty/objc_setProperty, as these will have to retain/copy/autorelease the objects as needed and further perform spinlocking for atomic properties where necessary. This can easily get very expensive and I'm not talking about being 50% slower.
Let's try this:
CFAbsoluteTime cft;
unsigned const kRuns = 1000 * 1000 * 1000;
cft = CFAbsoluteTimeGetCurrent();
for (unsigned i = 0; i < kRuns; i++) {
testIVar = i;
}
cft = CFAbsoluteTimeGetCurrent() - cft;
NSLog(#"1: %.1f picoseconds/run", (cft * 10000000000.0) / kRuns);
cft = CFAbsoluteTimeGetCurrent();
for (unsigned i = 0; i < kRuns; i++) {
[self setTestIVar:i];
}
cft = CFAbsoluteTimeGetCurrent() - cft;
NSLog(#"2: %.1f picoseconds/run", (cft * 10000000000.0) / kRuns);
Output:
1: 23.0 picoseconds/run
2: 98.4 picoseconds/run
This is 4.28 times slower and this was a non-atomic primitive int, pretty much the best case; most other cases are even worse (try an atomic NSString * property!). So if you can live with the fact that each ivar access is 4-5 times slower than it could be, using properties is fine (at least when it comes to performance), however, there are plenty of situations where such a performance drop is completely unacceptable.
Update 2015-10-20
Some people argue, that this is not a real world problem, the code above is purely synthetic and you will never notice that in a real application. Okay then, let's try a real world sample.
The code following below defines Account objects. An account has properties that describe name (NSString *), gender (enum), and age (unsigned) of its owner, as well as a balance (int64_t). An account object has an init method and a compare: method. The compare: method is defined as: Female orders before male, names order alphabetically, young orders before old, balance orders low to high.
Actually there exists two account classes, AccountA and AccountB. If you look their implementation, you'll notice that they are almost entirely identical, with one exception: The compare: method. AccountA objects access their own properties by method (getter), while AccountB objects access their own properties by ivar. That's really the only difference! They both access the properties of the other object to compare to by getter (accessing it by ivar wouldn't be safe! What if the other object is a subclass and has overridden the getter?). Also note that accessing your own properties as ivars does not break encapsulation (the ivars are still not public).
The test setup is really simple: Create 1 Mio random accounts, add them to an array and sort that array. That's it. Of course, there are two arrays, one for AccountA objects and one for AccountB objects and both arrays are filled with identical accounts (same data source). We time how long it takes to sort the arrays.
Here's the output of several runs I did yesterday:
runTime 1: 4.827070, 5.002070, 5.014527, 5.019014, 5.123039
runTime 2: 3.835088, 3.804666, 3.792654, 3.796857, 3.871076
As you can see, sorting the array of AccountB objects is always significant faster than sorting the array of AccountA objects.
Whoever claims that runtime differences of up to 1.32 seconds make no difference should better never do UI programming. If I want to change the sorting order of a large table, for example, time differences like these do make a huge difference to the user (the difference between an acceptable and a sluggish UI).
Also in this case the sample code is the only real work performed here, but how often is your code just a small gear of a complicated clockwork? And if every gear slows down the whole process like this, what does that mean for the speed of the whole clockwork in the end? Especially if one work step depends on the output of another one, which means all the inefficiencies will sum up. Most inefficiencies are not a problem on their own, it's their sheer sum that becomes a problem to the whole process. And such a problem is nothing a profiler will easily show because a profiler is about finding critical hot spots, but none of these inefficiencies are hot spots on their own. The CPU time is just averagely spread among them, yet each of them only has such a tiny fraction of it, it seems a total waste of time to optimize it. And it's true, optimizing just one of them would help absolutely nothing, optimizing all of them can help dramatically.
And even if you don't think in terms of CPU time, because you believe wasting CPU time is totally acceptable, after all "it's for free", then what about server hosting costs caused by power consumption? What about battery runtime of mobile devices? If you would write the same mobile app twice (e.g. an own mobile web browser), once a version where all classes access their own properties only by getters and once where all classes access them only by ivars, using the first one constantly will definitely drain the battery much faster than using the second one, even though they are functional equivalent and to the user the second one would even probably even feel a bit swifter.
Now here's the code for your main.m file (the code relies on ARC being enabled and be sure to use optimization when compiling to see the full effect):
#import <Foundation/Foundation.h>
typedef NS_ENUM(int, Gender) {
GenderMale,
GenderFemale
};
#interface AccountA : NSObject
#property (nonatomic) unsigned age;
#property (nonatomic) Gender gender;
#property (nonatomic) int64_t balance;
#property (nonatomic,nonnull,copy) NSString * name;
- (NSComparisonResult)compare:(nonnull AccountA *const)account;
- (nonnull instancetype)initWithName:(nonnull NSString *const)name
age:(const unsigned)age gender:(const Gender)gender
balance:(const int64_t)balance;
#end
#interface AccountB : NSObject
#property (nonatomic) unsigned age;
#property (nonatomic) Gender gender;
#property (nonatomic) int64_t balance;
#property (nonatomic,nonnull,copy) NSString * name;
- (NSComparisonResult)compare:(nonnull AccountB *const)account;
- (nonnull instancetype)initWithName:(nonnull NSString *const)name
age:(const unsigned)age gender:(const Gender)gender
balance:(const int64_t)balance;
#end
static
NSMutableArray * allAcocuntsA;
static
NSMutableArray * allAccountsB;
static
int64_t getRandom ( const uint64_t min, const uint64_t max ) {
assert(min <= max);
uint64_t rnd = arc4random(); // arc4random() returns a 32 bit value only
rnd = (rnd << 32) | arc4random();
rnd = rnd % ((max + 1) - min); // Trim it to range
return (rnd + min); // Lift it up to min value
}
static
void createAccounts ( const NSUInteger ammount ) {
NSArray *const maleNames = #[
#"Noah", #"Liam", #"Mason", #"Jacob", #"William",
#"Ethan", #"Michael", #"Alexander", #"James", #"Daniel"
];
NSArray *const femaleNames = #[
#"Emma", #"Olivia", #"Sophia", #"Isabella", #"Ava",
#"Mia", #"Emily", #"Abigail", #"Madison", #"Charlotte"
];
const NSUInteger nameCount = maleNames.count;
assert(maleNames.count == femaleNames.count); // Better be safe than sorry
allAcocuntsA = [NSMutableArray arrayWithCapacity:ammount];
allAccountsB = [NSMutableArray arrayWithCapacity:ammount];
for (uint64_t i = 0; i < ammount; i++) {
const Gender g = (getRandom(0, 1) == 0 ? GenderMale : GenderFemale);
const unsigned age = (unsigned)getRandom(18, 120);
const int64_t balance = (int64_t)getRandom(0, 200000000) - 100000000;
NSArray *const nameArray = (g == GenderMale ? maleNames : femaleNames);
const NSUInteger nameIndex = (NSUInteger)getRandom(0, nameCount - 1);
NSString *const name = nameArray[nameIndex];
AccountA *const accountA = [[AccountA alloc]
initWithName:name age:age gender:g balance:balance
];
AccountB *const accountB = [[AccountB alloc]
initWithName:name age:age gender:g balance:balance
];
[allAcocuntsA addObject:accountA];
[allAccountsB addObject:accountB];
}
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
#autoreleasepool {
NSUInteger ammount = 1000000; // 1 Million;
if (argc > 1) {
unsigned long long temp = 0;
if (1 == sscanf(argv[1], "%llu", &temp)) {
// NSUIntegerMax may just be UINT32_MAX!
ammount = (NSUInteger)MIN(temp, NSUIntegerMax);
}
}
createAccounts(ammount);
}
// Sort A and take time
const CFAbsoluteTime startTime1 = CFAbsoluteTimeGetCurrent();
#autoreleasepool {
[allAcocuntsA sortedArrayUsingSelector:#selector(compare:)];
}
const CFAbsoluteTime runTime1 = CFAbsoluteTimeGetCurrent() - startTime1;
// Sort B and take time
const CFAbsoluteTime startTime2 = CFAbsoluteTimeGetCurrent();
#autoreleasepool {
[allAccountsB sortedArrayUsingSelector:#selector(compare:)];
}
const CFAbsoluteTime runTime2 = CFAbsoluteTimeGetCurrent() - startTime2;
NSLog(#"runTime 1: %f", runTime1);
NSLog(#"runTime 2: %f", runTime2);
}
return 0;
}
#implementation AccountA
- (NSComparisonResult)compare:(nonnull AccountA *const)account {
// Sort by gender first! Females prior to males.
if (self.gender != account.gender) {
if (self.gender == GenderFemale) return NSOrderedAscending;
return NSOrderedDescending;
}
// Otherwise sort by name
if (![self.name isEqualToString:account.name]) {
return [self.name compare:account.name];
}
// Otherwise sort by age, young to old
if (self.age != account.age) {
if (self.age < account.age) return NSOrderedAscending;
return NSOrderedDescending;
}
// Last ressort, sort by balance, low to high
if (self.balance != account.balance) {
if (self.balance < account.balance) return NSOrderedAscending;
return NSOrderedDescending;
}
// If we get here, the are really equal!
return NSOrderedSame;
}
- (nonnull instancetype)initWithName:(nonnull NSString *const)name
age:(const unsigned)age gender:(const Gender)gender
balance:(const int64_t)balance
{
self = [super init];
assert(self); // We promissed to never return nil!
_age = age;
_gender = gender;
_balance = balance;
_name = [name copy];
return self;
}
#end
#implementation AccountB
- (NSComparisonResult)compare:(nonnull AccountA *const)account {
// Sort by gender first! Females prior to males.
if (_gender != account.gender) {
if (_gender == GenderFemale) return NSOrderedAscending;
return NSOrderedDescending;
}
// Otherwise sort by name
if (![_name isEqualToString:account.name]) {
return [_name compare:account.name];
}
// Otherwise sort by age, young to old
if (_age != account.age) {
if (_age < account.age) return NSOrderedAscending;
return NSOrderedDescending;
}
// Last ressort, sort by balance, low to high
if (_balance != account.balance) {
if (_balance < account.balance) return NSOrderedAscending;
return NSOrderedDescending;
}
// If we get here, the are really equal!
return NSOrderedSame;
}
- (nonnull instancetype)initWithName:(nonnull NSString *const)name
age:(const unsigned)age gender:(const Gender)gender
balance:(const int64_t)balance
{
self = [super init];
assert(self); // We promissed to never return nil!
_age = age;
_gender = gender;
_balance = balance;
_name = [name copy];
return self;
}
#end
Semantics
What #property can express that ivars can't: nonatomic and copy.
What ivars can express that #property can't:
#protected: public on subclasses, private outside.
#package: public on frameworks on 64 bits, private outside. Same as #public on 32 bits. See Apple's 64-bit Class and Instance Variable Access Control.
Qualifiers. For example, arrays of strong object references: id __strong *_objs.
Performance
Short story: ivars are faster, but it doesn't matter for most uses. nonatomic properties don't use locks, but direct ivar is faster because it skips the accessors call. For details read the following email from lists.apple.com.
Subject: Re: when do you use properties vs. ivars?
From: John McCall <email#hidden>
Date: Sun, 17 Mar 2013 15:10:46 -0700
Properties affect performance in a lot of ways:
As already discussed, sending a message to do a load/store is slower than just doing the load/store inline.
Sending a message to do a load/store is also quite a bit more code that needs to be kept in i-cache: even if the getter/setter
added zero extra instructions beyond just the load/store, there'd be a
solid half-dozen extra instructions in the caller to set up the
message send and handle the result.
Sending a message forces an entry for that selector to be kept in the method cache, and that memory generally sticks around in
d-cache. This increases launch time, increases the static memory
usage of your app, and makes context switches more painful. Since the
method cache is specific to the dynamic class for an object, this
problem increases the more you use KVO on it.
Sending a message forces all values in the function to be spilled to the stack (or kept in callee-save registers, which just means
spilling at a different time).
Sending a message can have arbitrary side-effects and therefore
forces the compiler to reset all of its assumptions about non-local memory
cannot be hoisted, sunk, re-ordered, coalesced, or eliminated.
In ARC, the result of a message send will always get retained, either by the callee or the caller, even for +0 returns: even if the
method doesn't retain/autorelease its result, the caller doesn't know
that and has to try to take action to prevent the result from getting
autoreleased. This can never be eliminated because message sends are
not statically analyzable.
In ARC, because a setter method generally takes its argument at +0, there is no way to "transfer" a retain of that object (which, as
discussed above, ARC usually has) into the ivar, so the value
generally has to get retain/released twice.
None of this means that they're always bad, of course — there are a
lot of good reasons to use properties. Just keep in mind that, like
many other language features, they're not free.
John.
The most important reason is the OOP concept of information hiding: If you expose everything via properties and thus make allow external objects to peek at another object's internals then you will make use of these internal and thus complicate changing the implementation.
The "minimal performance" gain can quickly sum up and then become a problem. I know from experience; I work on an app that really takes the iDevices to their limits and we thus need to avoid unnecessary method calls (of course only where reasonably possible). To aid with this goal, we're also avoiding the dot syntax since it makes it hard to see the number of method calls on first sight: for example, how many method calls does the expression self.image.size.width trigger? By contrast, you can immediately tell with [[self image] size].width.
Also, with correct ivar naming, KVO is possible without properties (IIRC, I'm not an KVO expert).
Properties vs. instance variables is a trade-off, in the end the choice comes down to the application.
Encapsulation/Information Hiding This is a Good Thing (TM) from a design perspective, narrow interfaces and minimal linkage is what makes software maintainable and understandable. It is pretty hard in Obj-C to hide anything, but instance variables declared in the implementation come as close as you'll get.
Performance While "premature optimisation" is a Bad Thing (TM), writing badly performing code just because you can is at least as bad. Its hard to argue against a method call being more expensive than a load or store, and in computational intensive code the cost soon adds up.
In a static language with properties, such as C#, calls to setters/getters can often be optimised away by the compiler. However Obj-C is dynamic and removing such calls is much harder.
Abstraction An argument against instance variables in Obj-C has traditionally been memory management. With MRC instance variables require calls to retain/release/autorelease to be spread throughout the code, properties (synthesized or not) keep the MRC code in one place - the principle of abstraction which is a Good Thing (TM). However with GC or ARC this argument goes away, so abstraction for memory management is no longer an argument against instance variables.
Properties expose your variables to other classes. If you just need a variable that is only relative to the class you're creating, use an instance variable. Here's a small example: the XML classes for parsing RSS and the like cycle through a bunch of delegate methods and such. It's practical to have an instance of NSMutableString to store the result of each different pass of the parse. There's no reason why an outside class would need to ever access or manipulate that string. So, you just declare it in the header or privately and access it throughout the class. Setting a property for it might only be useful to make sure there are no memory issues, using self.mutableString to invoke the getter/setters.
Backwards compatibility was a factor for me. I couldn't use any Objective-C 2.0 features because I was developing software and printer drivers that had to work on Mac OS X 10.3 as part of a requirement. I know your question seemed targeted around iOS, but I thought I'd still share my reasons for not using properties.
I'm working through examples in the book 'Visual Quick Start, Objective-C' by Holzner. I spend a lot of time with each example, getting the code debugged is the faster part, and then stepping through saying to myself why each line of code works, what each word in each line does and deciding why the author used one way of doing things versus another. Then I repeat the example with some story of my own. This seems to be a good way to move from being a structured programmer and to an oop-like one. It works with these examples because he just does one concept at a time. (I've worked part way through 2 other books and this idea did not work for me in those. Once I got confused by something, I just stayed confused. There were too many variables in the lengthier, more complex examples.)
In the current example (page 137), Holzner uses the word 'static'. I looked through examples in this book to decide what this word means. I also read the description in Bjarne Stroustrups' C++ Programming Language book (I understand that C++ and Objective-C are not exactly the same)
(Bjarne Stroustup p 145)
use a static variable as a memory,
instead of a global variable that 'might be accessed and corrupted by other functions'
Here is what I understand 'static' means as a result. I thought that meant that the value of a static variable would never change. I thought that meant it was like a constant value, that once you set it to 1 or 5 it couldn't be changed during that run.
But in this example piece of code, the value of the static variable does change. So I am really unclear on what 'static' means.
(Please ignore the 'followup question' I left commented in. I didn't want to change anything from my run, and risk creating a reading error
Thank you for any clues you can give me. I hope I didn't put too much detail into this question.
Laurel
.....
Program loaded.
run
[Switching to process 2769]
Running…
The class count is 1
The class count is 2
Debugger stopped.
Program exited with status value:0.
.....
//
// main.m
// Using Constructors with Inheritance
//Quick Start Objective C page 137
//
#include <stdio.h>
#include <Foundation/Foundation.h>
#interface TheClass : NSObject
// FOLLOWUP QUESTION - IN last version of contructors we did ivars like this
//{
// int number;
//}
// Here no curly braces. I THINK because here we are using 'static' and/or maybe cuz keyword?
// or because in original we had methods and here we are just using inheirted methods
// And static is more long-lasting retention 'wise than the other method
// * * *
// Reminder on use of 'static' (Bjarne Stroustup p 145)
// use a static variable as a memory,
// instead of a global variable that 'might be accessed and corrupted by other functions'
static int count;
// remember that the + is a 'class method' that I can execute
// using just the class name, no object required (p 84. Quick Start, Holzner)
// So defining a class method 'getCount'
+(int) getCount;
#end
#implementation TheClass
-(TheClass*) init
{
self = [super init];
count++;
return self;
}
+(int) getCount
{
return count;
}
#end
// but since 'count' is static, how can it change it's value? It doeeessss....
int main (void) {
TheClass *tc1 = [TheClass new] ;
printf("The class count is %i\n", [TheClass getCount]);
TheClass *tc2 = [TheClass new] ;
printf("The class count is %i\n", [TheClass getCount]);
return 0;
}
"static" is not the same thing as C++ "const". Rather it's a statement that a variable be declared only once and is to remain (hence static) in memory. Say you have a function:
int getIndex()
{
static int index = 0;
++index;
return index;
}
In this case the "static" tells the compiler to retain the index value in memory. Everytime its accessed it is changed: 1,2,3,... .
Compare this to:
int getIndex()
{
int index = 0;
++index;
return index;
}
This will return the same value each time as the index variable is being created each time: 1,1,1,1,1,... .
To clarify No one in particular's answer even further, a variable that is static will remain the same throughout all instances of objects, between method calls, etc.
For instance, declaring the following method:
- (int)getNumber {
static int number = 0;
return ++number;
}
will return 1, 2, 3, 4, etc., across all instances of the given class at any given time. Neat, eh?
static means many things in C / C++ / Objective-C.
Objective-C follows C closely. In C++, static means more things than in C / Objective-C. So, don't judge what static does in Obj-C by what Bjarne Stroustrup says (who is the inventor of C++).
In C and Objective-C, two main meanings of static are
For a variable / function in the file level, it makes a variable / function invisible from other translation units (i.e. other source files compiled into the same program.) It doesn't mean its constant.
For a variable declared inside a function, it makes a variable not to reside in a stack but in a more persistent location, as explained by no one in particular.
In C++, in addition to this meaning, a static member in a class means it belongs to the class, not to an instance. This meaning is completely unrelated to the other meaning; in the olden days, people didn't want to introduce more reserved words in the language, so they just abused the same reserved words in different contexts to mean completely unrelated things. Another notorious example is the usage of the word virtual.
In any case, static doesn't mean it's constant.
Anyway, in a programming language, a thing means whatever the implementers or the standard committee members decide it to mean. Therefore I find it always helpful to read the standard. Just look for the word static in that PDF. You'll learn everything about static keyword in the programming language C there.
In Java, it is very easy to code the following design:
public abstract class Pizza {
public static final Pizza.NULL = new Pizza() {
/* "null" implementations */
}
/* actual/abstract implmentations */
}
What is the preferred method to attain the same efficient scenario in Objective-C? I have been unable to find any documentation on the subject, and I have tried a couple different scenarios with static const, #define etc. but none of them seem to work out as well as the Java method above.
I would like to avoid writing a concrete NullPizza class that has a static method to obtain the singleton instance, as it seems more 'proper' for it to be some final property/field of the highest-level interface. (Pizza, in this case.)
Edit: While I understand how the NULL pattern specifically would be handled due to Obj-C's unique method of handling method calls to 'nil', what about other static common instances, such as Response.YES and Response.NO? (See comments for discussion.)
There is no need for this type of pattern in Objective-C because it is not considered a runtime error to message a nil instance of a class. If the method has a defined return type, there are defined returns from messaging a nil object (e.g., methods that return an integer return 0 when messaging a nil object).
There are two things which can help here. The first is nil, the Objective-C equivalent of the Java NULL pointer - it can actually receive messages and respond to them. It will always return nil if the return value is an object, and 0 if the return value is some primitive type. Therefore if the Null behaviour of your object is "do nothing" you can easily just use nil as the Null value.
The other thing which is helpful is for when you need to store a placeholder or null value in a container object - these usually throw exceptions if you attempt to add nil as a value. Instead you can use the singleton +[NSNull null], which does nothing except act as a "this space intentionally left blank" object.
With these two weapons at your disposal there should be no reason to write a null instance of a custom class :-)
For your Response.YES and Response.NO, I assume you have instances that you do want to change, rather than just making all Response properties read-only.
A common pattern in Cocoa is to have both immutable and mutable versions of a class (NSArray versus NSMutableArray). For your response example, it would make sense to have an immutable Response class that has the static YES and NO methods, and a MutableResponse subclass that exposes setters for those times where you do want objects to change them. Does this cover your second example?
I don't think there is an easy way to provide this implementation. You're asking for something that is a language feature of Java to be implemented in Objective-C - you can do it but you have to write the code that is in the Java runtime yourself - there is nothing to stop you doing this but it's not something the language has built in.
It's a bit like asking "How do I show a Windows style 'one menu per window" UI in Cocoa' - you can do it but it's not provided for free from the framework. Or, "how can I easily implement Objective-C's nil pointer handling in Java?"
If you really want to see this type of functionality I think you should follow the NSArray/NSMutableArray design pattern. Declare a superclass that can handle all of your special cases:
#interface NullPizza : NSObject
{
}
- (BOOL)areYouANullPizza;
#end
and then subclass with your real Pizza and include a newNullPizza class method (which is just syntax sugar):
#interface Pizza : NullPizza
{
}
+ (Pizza*)Null;
#end
#implementation Pizza
+ (Pizza*)newNullPizza
{
return [[NullPizza]alloc init]; // Singleton code left as an exercise.
}
- (BOOL)areYouANullPizza;
{
return NO;
}
#end
Note that if you wanted to implement a +(Pizza*)NULL method on Pizza you should autorelease the new NullPizza you create.
Disclaimer, I typed this code straight into SO. I'd be surprised if it compiles but you get the idea.