I’m sure this is a simple one, but it’s been elusive so far, and I’m stumped ...
How do I declare an Ivar so that it’s accessible from ALL Classes in a project?
[Don’t know if it matters, but the ivar in question is (an instance of) my Model class, whose data needs to be accessible to various view controllers.]
Best as I can tell from "The Scope of Instance Variables” in The Objective-C 2.0 Programming Language
... this would be by using the “#public” directive.
So I’ve tried this in the #interface block where the ivar is declared:
#interface ...
...
#public
ModelClass *theModel;
#end
... But when I try to refer to “theModel” in a different class, the compiler doesn’t auto-complete, and when I type it in anyway, the compiler shows:
“Error: ‘theModel’ undeclared (first use in this function)”.
I assume this is a question of Scope, and that I haven’t made the ivar available appropriately, but how? Somehow I need to access this, or make its pointer available somehow.
Any ideas would be VERY much appreciated. Many thanks!
Perhaps you forgot to put the instance variable inside the braces of the class where all instance variable declarations go?
#interface Foo : NSObject {
// other instance variable declarations
#public
ModelClass *theModel;
}
// method and property declarations
#end
Also, can you show us the code of how you are trying to access the instance variable from elsewhere? The proper syntax should be:
myFooInstance->theModel
where myFooInstance is a value of type "Foo *"
I make properties available to all views managed by a Tab Bar via a singleton representing my data model. This is efficient and allows all Views access to the data (as well as any other application elements. Creating the singleton is straightforward (there are a ton of examples on S.O.). The you just request the instance and get the property values you need.
Here is a framework fro creating the Singleton. The key points are the static instance and the fact that you do the initialization as [[self alloc] init];. This will ensure the object gets cleaned up correctly. All the methods at the bottom of the class are standard from the SDK Docs to make sure release calls are ignored (because the object is shared globally).
Singleton Boilerplate (ApplicationSettings.m):
static ApplicationSettings *sharedApplicationSettings = nil;
+ (ApplicationSettings*) getSharedApplicationSettings
{
#synchronized(self) {
if (sharedApplicationSettings == nil) {
[[self alloc] init]; // assignment not done here
}
}
return sharedApplicationSettings;
}
+ (id)allocWithZone:(NSZone *)zone
{
#synchronized(self) {
if (sharedApplicationSettings == nil) {
sharedApplicationSettings = [super allocWithZone:zone];
return sharedApplicationSettings; // assignment and return on first allocation
}
}
return nil; //on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain
{
return self;
}
- (unsigned)retainCount
{
return UINT_MAX; //denotes an object that cannot be released
}
- (void)release
{
//do nothing
}
- (id)autorelease
{
return self;
}
You cannot access iVars from any other class.
You have to declare a getter/setter method to change or view a variable from another class - what you are really looking for are properties, that make it easier to define and access these getter/setter methods.
In your example above, you'd have the property defined just after the block that defines the local variable in the header file:
#property (nonatomic, retain) ModelClass *theModel;
In the implementation file you'd have the getter/setter created with the #synthesize statement just after the #implementation line:
#synthesize theModel;
Then if you have an instance of your class created, you access the class instance variable like so:
myInstance.theModel = [[[ModelClass alloc] init] autorelease];
The reason #public & #private are in there are to define visibility for subclasses (which, being extensions of that class type also get all the class local variables defined by a superclass), not for any random class.
The standard Objective-C way of doing it is to have a class method that returns the ivar
In your .h file:
+ (id)defaultModel;
and in your .m file:
static ModelClass * defaultModelInstance;
#implementation ModelClass
+ (id)defaultModel {
if (!defaultModelInstance) {
defaultModelInstance = [[ModelClass alloc] init];
}
return defaultModelInstance;
}
#end
although this will need tweaking if you need a specific ivar instead of just "a ivar that's always the same"
this type of design is used by many Cocoa classes i.e. [NSWorkspace sharedWorkspace]
Think a C global variable.
Adding:
extern ModelClass* theModel;
after the #end in the header will make the variable visible anywhere you include the header.
In the ModelClass.cpp file add:
ModelClass* theModel;
before the class implementation.
The variable will still have a value of nil until you allocate and initialize it though and you will be resposible for ensuring that it gets deallocated at the correct time.
THANK YOU ALL for the very helpful discussion on this topic! Clearly there are several ways to approach things here, so this is a very useful assortment of techniques.
Just to let y'all know that in researching this issue further, I ran across a couple of other very helpful pages, listed below. They include mention of the NSNotificationCenter, which I hadn't heard of before; as well as the idea of the "dependency injection" design pattern.
The idea is to keep "low coupling"(1) between the classes, making the code more modular & better for unit testing.
And while the 'notification' pattern sounds like a great idea, in this case it may be a bit overkill, considering that I only need ONE instance of the data model throughout the run of the app, and it doesn't change throughout.
Finally, even though the "#public" compiler directive is well-documented in Apple's Obj-C guide(2), I later found a fascinating edict in a different doc stating that it shouldn't be used! Quoted from Apple's own Cocoa Fundamentals(3):
"Give the proper scope to your instance variables. Never scope a variable as #public as this violates the principle of encapsulation. ..."
(Strange that they don't mention this in their 'Objective-C 2.0' guide where the directive is actually explained.)
Anyway, here are a couple of other links I found to be full of some great insights as well. FYI:
S.O.: "What’s the best way to
communicate between
viewcontrollers?"(4) <<
CocoaWithLove: "Five approaches to
listening, observing and notifying in
Cocoa"(5)
CocoaWithLove: "Singletons,
AppDelegates and top-level data"(6)
Hope these help. Anyway, thank you all again!
Best,
rond
P.S. Yikes! It won't let me post more than one inline hyperlink, so I'm listing them here instead. Obviously, they’re all prefixed by “http://” ... :O
(1): en.wikipedia.org/wiki/Coupling_(computer_science)
(2): developer.apple.com/DOCUMENTATION/Cocoa/Conceptual/ObjectiveC/Articles/ocDefiningClasses.html#//apple%5Fref/doc/uid/TP30001163-CH12-TPXREF127
(3): developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/AddingBehaviortoaCocoaProgram/AddingBehaviorCocoa.html#//apple_ref/doc/uid/TP40002974-CH5-SW12
(4): stackoverflow.com/questions/569940/whats-the-best-way-to-communicate-between-viewcontrollers
(5): cocoawithlove.com/2008/06/five-approaches-to-listening-observing.html
(6): cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html
Related
i have a general question about properties and ivars.
ive seen many different examples to use properties and it confuses me a bit.
method 1 only using a property without a corresponding ivar.
#property (...) Type *name;
#synthesize name;
method 2 using a property and an ivar
#interface{
Type *ivarName;
}
#property (...) Type *name;
#synthesize name = ivarName;
method 3 ignoring properties and working with ivars
#interface{
Type *ivarName;
}
ivar = ...;
i currently use method 1 for most things i do, it just works. but i have startet to wonder if i might be missing something here. i have read a lot of questions about ivars VS properties, but none of them seemed to really care about how they work together.
in most sample projects i've seen method 2 is used. so my question is: is there any advantage in defining a property and an ivar, and then assign the property to the ivar, than just having a property?
is the solution as simple as: only with a property can an ivar be set from 'outside'?
i have read: Must every ivar be a property? and Property vs. ivar in times of ARC but was not able to draw a final conclusion.
is the solution as simple as: only with a property can an ivar be set from 'outside'?
Essentially, yes. Ivars in Obj-C are (by default) "protected", meaning that the compiler won't allow you to access them externally to the object's own code. For example, given the following class declaration:
#interface Dunstable : NSObject
{
NSString * crunk;
}
#end
You might think you'd be able to access the ivar after creating the object, but trying results in an error:
Dunstable * d = [[Dunstable alloc] init];
d->crunk = #"Forsooth"; // Error: "Instance variable 'crunk' is protected
That's why ObjC uses accessor methods. Defining them manually was mandatory before the advent of declared properties:
#implementation Dunstable
- (NSString *)crunk {
return crunk; // implicit ivar access, i.e. self->crunk
}
- (void)setCrunk: (NSString *)newCrunk {
[newCrunk retain];
[crunk release];
crunk = newCrunk;
}
#end
Now, using the #property and #synthesize directives creates those accessor methods for you (as well as the variable itself). (The manual memory management in the setter is of course also obsolete under ARC.)
It is possible to make an ivar that's accessible from outside the object:
#interface Dunstable : NSObject
{
#public
NSNumber * nonce;
}
#end
Dunstable * d = [[Dunstable alloc] init];
d->nonce = [NSNumber numberWithInt:2]; // Works fine
but this isn't considered good Objective-C style.
The Objective-C Programming Language doc contains a "Historical Note" about this:
Note: Historically, the interface required declarations of a class’s instance variables, the data structures that are part of each instance of the class. These were declared in braces after the #interface declaration and before method declarations:
[...]
Instance variables represent an implementation detail, and should typically not be accessed outside of the class itself. Moreover, you can declare them in the implementation block or synthesize them using declared properties. Typically you should not, therefore, declare instance variables in the public interface and so you should omit the braces.
This is a pretty big change (I was actually surprised that there's no syntax given for ivars declared in #interface anymore in that doc), but it's definitely for the better. You should use declared properties; they do the right thing and make your code cleaner and safer.
When you write:
#synthesize name;
an ivar name is created, and it has the same name as the property. So you can access it with or without self.
In reality if you write
self.name = #"hello";
you are accessing the property, and if you write
name = #"hello";
you are accessing the ivar. Most people (including me) will advise you not to access your ivars directly unless it is really what you want: for example, if you are creating a custom setter or getter for the property. Otherwise always access the property with self.
In my case I always do:
#synthesize name = _name;
The advantage of this approach is that when you forget to write self instead of accessing the ivar you will get an error telling you that the ivar name doesn't exist.
You should never access ivars directly from outside of a class. That's the main function of properties--defining accessor methods for use by other objects. However, it's also good practice to use your accessors from within the same class--this way you can ensure that any appropriate side effects take place (memory management is an obvious example, if you aren't using ARC).
So, Method 3 is usually wrong. Method 1 is roughly equivalent to Method 2--that is, behind the scenes, the runtime is basically creating an ivar for you. Note also that you can set the name of that ivar even if you didn't explicitly define it:
#interface{
//No ivar here!
}
#property (...) Type *name;
#synthesize name = ivarName;
From the second link you supplied, Property vs. ivar in times of ARC, the comment by Denis Mikhaylov on the accepted answer is very telling. He points out that with your case 3, that you can access the iVar through:
classInstance->iVar = #"New value"
But this is considered bad practice. So i'd restate your point as:
Only with a property should an ivar be set from 'outside'
I am some what confused as to the difference between accessing an instance variable via self or just by name (when working inside the class).
For instance, take this class:
//In .h file:
#interface Register : NSObject {
NSString *mName;
}
- (id) initWithName:(NSString *) name;
//In .m file:
- (id) initWithName:(NSString *)name
{
if (self == [super init])
{
mName = name;
}
return self;
}
What's the difference between accessing the instance variable via
self.mName = name;
vs
mName = name;
Which isn't a #property and is not #sythenize'd.
Say it is this though, per this example:
//In .h file:
#interface Manange_My_ViewsViewController : UIViewController {
IBOutlet UILabel *countLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *countLabel;
//In .m file:
#synthesize countLabel;
- (void) updateLabel:(NSUInteger)count
{
countLabel.text = [NSString stringWithFormat:#"%d", count];
}
But say I accessed countLabel as:
self.countLabel
What would be the difference?
Edit: Third example per users' answer:
Say it the iVar wasn't an IBOutlet:
//In .h file:
#interface Fake : NSObject {
NSString *mVar;
}
#property (nonatomic, retain) NSString *mVar;
//In .m file:
#synthesize mVar;
mVar = #"";
VS
self.mVar = #"";
Or is it the same - that in the first we are accessing the actual instance variable and in the second we're actually going through the auto created setter (via #synthesize)?
Thanks all!
Edit: Update in response to Peter Hosey ...
So your thinking the convention of mVarName is bad? I took that from my C++ days.
But what about the case when you do?
-(void) someMethod:(int) x
{
x = x;
}
You can't do that (Say 'x' is also a class variable)
But you can do:
-(void) someMethod:(int) x
{
mX = x;
}
But your saying its better to do:
-(void) someMethod:(int) x
{
self.x = x;
}
What's the difference between accessing the instance variable via
self.mName = name;
vs
mName = name;
The first is property access syntax. It translates to an accessor message to the object (in this case, self). That is, that statement implicitly translates to this message expression statement:
[self setMName:name];
(Awkward accessor names like that are why “mName” is a poor name for a property. There is property declaration syntax to work around that, letting you name the property “name” and your instance variable “mName” and map one to the other.)
The second example directly accesses the instance variable—no accessor message.
Which isn't a #property and is not #sythenize'd.
Say it is this though, …
If no property named “mName” is declared for a class, then you can't use property access syntax to access a property by that name on an instance of that class.
And it doesn't matter whether you synthesize the accessors, hand-wave them to a superclass with #dynamic, or define them yourself. That's how the object will respond to the accessor message, but the accessor message the compiler generates will be no different (since a property access could just as easily come from outside the class as from inside it).
Say it the iVar wasn't an IBOutlet:
That doesn't matter. IBOutlet only means anything to IB. Everything else doesn't care.
In fact, IBOutlet is currently just a macro that expands to nothing. After your code gets preprocessed, the word “IBOutlet” is no longer there, so the compiler never sees it. That's how little a difference it makes to anything but IB: None at all.
Edit in response to question edit
I said mName is bad as a property name, because of the accessor names that follow from it. The name of an instance variable is a separate issue, particularly since the property and ivar don't have to have the same name.
For a variable, be it an instance variable or a local variable, the choice of name or m_name or mName is purely a style choice.
someMethod: is generally the accessor, setX:. Within that method, self.x = x, which is [self setX:x], causes infinite recursion. So don't do that.
When someMethod: isn't the accessor (or init or dealloc), using the property is just fine and generally preferable. However, in that case, you're not likely to give one of its arguments the same name as an instance variable. When such a case could occur, name the local variable more specifically, because its purpose is more specific. This, too, is a style issue.
When it is the accessor, I name the local variable newX, having named the instance variable the same as the property, x. This is my own personal style; as I said, naming the property x, the ivar mX, and the local variable x is fine too (aside from the excessive brevity of this example).
OK, first off is the basic difference:
mVar = var;
This is just changing a value. That's it.
self.mVar = var;
This is equivalent to:
[self setMVar:var];
In other words, one invokes a method, the other does not. Using the #property syntax can give you some really neat benefits. For example, you get key-value coding compliance for free. That means that another object can observe this object's mVar property, and be automatically notified whenever it changes, without you doing anything. You don't get this if you just access the ivar directly. (Unless, of course, you implement it yourself. But why would you do that?)
You also get semi-free memory management. If you declare a property as (retain), then you don't have to [newValue retain] yourself. The synthesized method will do this for you (in both cases, you'd still have to [ivar release] in your dealloc method).
You also can get some degree of thread safety. If you don't declare a property as (nonatomic), then it is (by default) atomic (although that keyword does not exist; it's implied). That means that reading/updating the value of the property is an atomic operation. If you were to just access the ivar directly, you'd have to implement the atomicity yourself with a lock.
Basically, using the synthesized methods gets you some really neat stuff for free. The only reason I'd say to not use the #property syntax is if you have irrefutable evidence that invoking those methods is a bottleneck in your code. However, you'll be really hard pressed to come up with a situation where that would be the case.
First of all, with a read-only property--which an IBOutlet essentially is--it does not matter as much.
The key difference is that the property is actually calling the accessor method while the instance variable is being accessed directly.
Thus, for setting a retain property, using self and the accessor will release the old object and retain the new one. Setting the instance variable directly will NOT impact the retain counts of any objects.
Using #synthesize will generate standard accessors for you.
The key reason to use properties is that, since they are accessors, they can be read and/or modified from outside the class.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does an underscore in front of a variable in a cocoa objective-c class work?
I've noticed that in a lot of the reference materials out there, I see that a lot of the time, variables are named _variable in the .h file, then are #synthesize'd in the .m file as
#synthesize variable = _variable;
Why is this done? What am I missing?
Thanks!
There is not consensus on this. Some people like to use it for clarity to separate out class variables, and as another responder noted to avoid conflict with incoming parameter names. Even in Apple sample code the use is mixed.
However, I greatly prefer to not use the _ prefix and have two strong reasons:
1) Some people think the _ is a good indicator of "private". My take is that NO class local variable should be accessed without a setter/getter (property) and thus they are ALL private - given that why not name them in a way easier to read and use autocomplete on? Any overlap in names from parameters is quickly revealed by the compiler, and avoided through more thoughtful naming of parameters (or internal variables).
2) (even better reason) - if you use "refactor" in XCode on an internal class var that is named the same as the property used to access it, the property and synthesize statement will also be renamed. If you use refactor on a class variable prefixed with an _, the property name will not be changed - just the synthesize mapping to the internal name. I pretty much never want the name to vary from the property to the real variable it exposes access to. That alone makes me never want to use _ as a variable prefix, since being able to shift names is just about the most useful thing you can do to improve code clarity.
Using that syntax is an option to make it more clear that the ivar and property are different things.
To code external to the class, there is no difference since it uses the property.
For code in the implementation of the class itself, it can make it more clear when the ivar is used versus the property.
For example, say we have an ivar/property for an NSNumber object:
#interface MyClass : NSObject {
NSNumber *num;
}
#property (nonatomic, retain) NSNumber *num;
- (void)doSomething;
#end
#implementation MyClass
#synthesize num;
- (void)doSomething {
// set the property, num is properly retained
self.num = [NSNumber numberWithInteger:1];
// accidentally set the ivar, num is NOT retained
num = [NSNumber numberWithInteger:2];
}
#end
and now using a different name for the ivar and property:
#interface MyClass : NSObject {
NSNumber *i_num;
}
#property (nonatomic, retain) NSNumber *num;
- (void)doSomething;
#end
#implementation MyClass
#synthesize num = i_num;
- (void)doSomething {
// set the property, num is properly retained
self.num = [NSNumber numberWithInteger:1];
// compiler error, there is no ivar named "num"
num = [NSNumber numberWithInteger:2];
// set the ivar, so it needs to be a retained object
i_num = [[NSNumber alloc] initWithInteger:3];
}
#end
Previous answers are missing the history behind this. Before Objective-C 2.0, there were no properties. So you’d have an object with instance variables like this:
#interface MyObject: NSObject {
NSArray *myArray;
}
#end
But how would you access them from other objects? the solution was to make setters and getters. But to avoid confusion, they would do it like this:
#interface MyObject: NSObject {
NSArray *_myArray;
}
- (NSArray *)myArray;
- (void)setMyArray:(NSArray *)myArray;
#end
The _ serves to clear up confusion between the instance variable _myArray and the method -myArray.
Sometimes people use mVarName (C++) and in Obj-c the style seems to be _varName.
One problem you can have, is imagine that your argument to a function is ...set:(int) x - BUT - you have an iVar called x...well your going to get the compiler crying about stuff like that - not to mention its confusing.
The m,_, whatever helps to show what are member properties of the class.
-(void) set:(int)x
{
x = x; // x is an ivar! heh
}
VS
-(void) set:(int)x
{
_x = x; // ahh I see!
}
This is purely convention. I suppose its common because when you make a method getter call like this:
[myObject variable]
you are actually calling a method, not accessing a variable directly. the _ in front makes it clear that you are talking about a variable. Personally, I find this syntax annoying and distracting. I find it unnecessary, but you are right, it does appear here and there.
I prefer not to use the '_' prefix because Apple does use it consistently. By avoiding the prefix I then have greater confidence that my ivars do not collide with Apple's when I extend a cocoa touch class. Since we do not have access to the base class' source this is really the only way I know of to avoid accidental reuse of existing private ivars.
Much like
Method names beginning with “_”, a single underscore character, are reserved for use by Apple.
My preference, following Google, is simply to append an underscore and explicitly synthesize (even if I'm reimplementing):
#synthesize varName=varName_;
If I see that trailing underscore outside of init..., dealloc or an accessor, I know something's fishy.
Update:
iPhone OS 3.1 has associated objects. However, the iPhone simulator does not. If you want to test associated objects code in the simulator, you should file a bug.
See my SO question here.
rdar://7477326
Snow Leopard now has associated objects.
Is there a way to accomplish something similar without associated objects? (Specifically for the iPhone.)
I am pretty sure I saw something like this a while back, but I can't remember where. Something about turning any object into a KVC container.
objc_setAssociatedObject() and friends were added to iPhone OS 3.1, so if you have the option of targetting just 3.1+ devices you can in fact do the exact same thing as on Snow Leopard...
If you can't you can create a static dictionary of associations and monkey patch out NSObjects dealloc method. For various technical reasons this solution cannot be made to work correctly in the presence of GC (which is why apple added the association stuff), but since iPhone does not support GC that is a non-issue.
If you are just starting work on this project I highly recommend using the runtime functions and targeting 3.1 plus, but if that is not an option here is an example of how you do it.
LGAssociativeStorage.h:
#import <pthread.h>
#import <Foundation/Foundation.h>
#interface NSObject (LGAssociativeStorage)
#property (retain) id associatedObject;
#end
LGAssociativeStorage.mm
#import <objc/runtime.h>
#import "LGAssociativeStorage.h"
/* We are using STL containers because:
1) Using Objective C containers can cause deallocs which cause recursion issues
2) STL containers are high perf containers that don't introduce external code dependencies
Ideally one could include a thread safe map implementation, but I don't need one currently
*/
#include <map>
typedef std::map<id,id> idMap_t;
typedef std::pair<id,id> idPair_t;
static NSMutableDictionary * data = nil;
static pthread_mutex_t data_lock = PTHREAD_MUTEX_INITIALIZER;
static IMP gOriginalNSObjectDealloc = nil;
static idMap_t associatedObjectMap;
static
void removeAssociatedObjectFromMap(id self) {
idMap_t::iterator iter = associatedObjectMap.find(self);
if( iter != associatedObjectMap.end() ) {
[iter->second release];
associatedObjectMap.erase(iter);
}
}
static
id newNSObjectDealloc(id self, SEL deallocSelector, ...) {
pthread_mutex_lock(&data_lock);
removeAssociatedObjectFromMap(self);
pthread_mutex_unlock(&data_lock);
return gOriginalNSObjectDealloc(self, deallocSelector);
}
static void initIfNecessary(void) {
if (!data) {
data = [[NSMutableDictionary alloc] init];
// The below line of code is abusive... in the future the Objective C runtime will use it as evidence
// that I am an unfit software engineer and take custody of all my code
gOriginalNSObjectDealloc = class_replaceMethod([NSObject class], #selector(dealloc), newNSObjectDealloc, "v#:");
}
}
#implementation NSObject (LGAssociativeStorage)
- (id) associatedObject {
id retval = nil;
pthread_mutex_lock(&data_lock);
initIfNecessary();
idMap_t::iterator iter = associatedObjectMap.find(self);
if( iter != associatedObjectMap.end() ) {
retval = iter->second;
}
pthread_mutex_unlock(&data_lock);
return retval;
}
- (void) setAssociatedObject:(id)object_ {
pthread_mutex_lock(&data_lock);
initIfNecessary();
removeAssociatedObjectFromMap(self);
[object_ retain];
associatedObjectMap.insert(idPair_t(self, object_));
pthread_mutex_unlock(&data_lock);
}
#end
You could always have them stored in a singleton.
There are no good ways to do this in a generic category.
You can easily add data for an object by having a global NSMutableDictionary that maps from any arbitrary NSObject to whatever data you want. The problem is there is no way to know when the object is deallocated, so you cannot tell (in general) when the data goes stale.
The only generic way to solve this is to use method swizzling to replace the NSObject dealloc method to report the deallocation of the object and release your associated data. I'm sure someone has done this, but its such a hideous hack it would be very hard to recommend as a valid appropach.
Now, if your objects in questions have some other way to monitor life cycle (ie, some deallocation hook, like a delegate objectWillClose method of some sort), then you can hook in to that to release your associated data and that would make the technique quite straight forward and legitimate.
I'll add an answer.
I found the original blog post, it was from Steve Degutis.
It basically involves replacing NSObject's methods for valueForUndefinedKey:, setValue:ForUndefinedKey:, and dealloc. Then using a static Dictionary to store any undefined keys.
Just about as nasty and fun as Louis's solution.
Notwithstanding concerns for concurrency issues, why not just use global variables ? Even using runtime objc_set/get AssociatedObject() methods aren't you passing a "global" static variable address in which case you still have concurrency issues wouldn't you?
I am using a singleton backbone in my application to handle accuring errors. They will be handled inside the singleton and broadcast a notification throughout the app when the error has been fixed. Anyways this is not what my question is about but when I pass a new error to the singleton object like this
[[SingletonErrors sharederrors] addError:ErrorDictionary_here];
I want ErrorDictionary_here to be a NSMutableDictionary protected by a given #protocol in my code so whenever I give my code to others in my team they get warnings about error information they might have forgotten to pass into the dictionary.
Is this even possible for starters because this is about adding protocols to setters and a getter is much more easy like
-(NSMutableArray< myprotocol > *)getmyError{
}
I hope some one can help me out.
I'm not seeking for passing objects (read class instances) instead of the dictionary just a protocol applied on my dictionary.
It is also possible to implement a protocol through a category like so:
#interface NSMutableDictionary_TD(ErrorExtensions) <ErrorProtocol>
#end
#implementation NSMutableDictionary(ErrorExtensions)
//implement the ErrorProtocol here
#end
If I understand what you're asking, you should be able to do this without too much hassle. In your singleton class SingletonErrors, you should have:
#interface SingletonErrors : NSObject {
// some definitions ...
// The current array of all errors. This can also be an NSMutableSet if you like
NSMutableArray *sharedErrors;
// more definitions ...
}
// some properties ...
#property(nonatomic,retain) NSMutableDictionary<ErrorProtocol> *sharedErrors;
// more properties ...
- (void)addError:(NSMutableDictionary<ErrorProtocol> *)newError;
#end
You should create the protocol to be implemented. In this sample protocol, let's say you want to provide a single method to check whether the object is valid - that is, the dictionary contains all the relevant information.
#protocol ErrorProtocol
- (BOOL)isValid;
#end
You'll then need to subclass NSMutableDictionary so that your class implements the ErrorProtocol protocol:
#interface MyMutableDictionary : NSMutableDictionary <ErrorProtocol> {
}
#end
#implementation MyMutableDictionary
- (BOOL)isValid {
// Do your validity checking here
return YES; // Obviously change this line
}
#end
Then, whenever you throw an error, you can pass in a new instance of MyMutableDictionary to SingletonErrors, and have it call the isValid selector on the MyMutableDictionary, since it's assured that the dictionary will conform to ErrorProtocol and responds to isValid:
- (void)addError:(NSMutableDictionary<ErrorProtocol> *)newError {
if([newError isValid]) {
// Add the new error to the current array of errors
[self.sharedErrors addObject:newError];
// Other code to "broadcast" the error would go here
} else {
// Some code to error out of adding the error would go here
}
}
Overall, what this solution does is:
Hold a NSMutableArray of all errors in SingletonErrors
Each error is an NSMutableDictionary that conforms to ErrorProtocol
The object we use for each error is MyMutableDictionary, a subclass of NSMutableDictionary
The protocol ErrorProtocol defines a method isValid that checks whether the error is OK to be added
The SingletonErrors object calls the isValid method and adds the error appropriately
Thats correct but the doesnt feel nice to me .. my solution merged with tim`s was
#implementation NSMutableArray (myAddition)
- (BOOL)isValid {
// Do your validity checking here
return YES; // Obviously change this line
}
#end
This saves a load of code .. Im a Objective C in blood and fains .. less is better :) .. thanks for your reply anyways because im sure this issue is not a basic objc issue. Its more advanced and i think loads of people will find this topic and see the fix and you fix is 100% right as well so thanks for that !..
My heart is to small to store the loving replies i get here :).