I was messing around in Objective-C earlier, and I ran into a quite common situation:
I had a class, which was not a singleton, that needed a variable shared between method calls, like static
, but each instance needed it's own variable. However, this variable only needed to be used in one particular method, we'll call it -foo
.
What I'd love to do, is have a macro, let's call it ivar
, which lets me do the following:
@implementation MyClass
-(foo)
{
ivar int someVal = 10; // default value, ivar scoped variable.
}
-(bar)
{
someVal = 5; // error, outside of `foo`'s scope.
}
@end
How the variable is defined does not matter to me (either a macro like OBJC_IVAR(Type, Name, Default)
or ivar someType someName = value
), as long as it meets the following requirements:
- Has thread safety
- Can have variable of same name (but different value) in another method
- Type-less (doesn't matter what type the variable is)
- Default Value support
- Variable can be declared in one line (I shouldn't have to write 15 lines of code just to put a variable in my code)
I am currently working on an Objective-C++ implementation myself, I was just wondering if anyone else had any thoughts (or existing tools) on how to do this.
Obviously, this doesn't have to be done with a true iVar. More likely, this should be done with associated objects at run-time, which also manages deallocation for us.
In that case, the variable is part of the object's state, and it's therefore most appropriate to use an instance variable (or a property). This is exactly what ivars are for, whether they're used in a dozen methods or just one.
My advice is to not do it at all. If your goal is to avoid clutter, don't go needlessly trying to add a new storage class to the language.
However, if you're determined to pursue this line, I'd look at using blocks instead of associated objects. Blocks get their own copies of variables that are scoped to the lifetime of the block. For example, you can do this:
and the output you get is:
Perhaps you can find a clever way to wrap that up in a macro, but it looks to me like a lot of trouble just to avoid declaring an instance variable.
After a lot of time spent, I believe I have a fully working solution in Objective-C++. Some of the features:
Simple variable declaration:
Possible ways to define an OBJC_IVAR:
Full Type Support with C++ templates (
__weak
,__strong
,__autoreleasing
,volatile
, etc. are all supported)Some minor cons to the implementation:
Objects must have an ownership specifier (limitation with C++ references:
Reference to non-const type 'id' with no explicit ownership
). Is easily fixed by adding__strong
,__weak
, or__autoreleasing
to the type of the variableImplementation is hard to read. Because it relies so much on C++ templates and Objective-C working together in harmony, it's difficult to just change 'one thing' and hope for it to work. I have added extensive comments to the implementation, so hopefully that frees some of the burden.
Method swizzling can confuse this majorly. Not the largest of issues, but if you start playing around with method swizzling, don't be surprised if you get unexpected results.
Cannot be used inside a C++ object. Unfortunately, C++ doesn't support runtime attributes, like objective-c does, so we cannot rely upon our variables being cleaned up eventually. For this reason, you cannot use OBJC_IVAR while inside a C++ object. I would be interested in seeing an implementation for that, though.
#line
can mess this up drastically, so don't use it.Version History
OBJC_IVAR_NAME
to rely only on the preprocessor. As a result, we cannot use__func__
.So, without further ado, here is the code:
OBJC_IVAR.hpp
NSValue+CppObject.h
NSValue+CppObject.m
Example Usage: