Storing any number of different classes in one property - objective-c

I have a collection of instances of different classes (9 to be precise), all with identical methods and properties, but each one performs a specific task.
I want to be able to switch between these different objects at any point. There maybe times when only a few of the objects get used, sometimes when they all get used, and other times when only one is used.
Ideally, I want a single property that could point to an instance of any of these objects. Ive tried doing something like this:
#property (nonatomic, strong) id * currentObj;
...
currentObj=[[ClassType3 alloc] init];
(ClassType3 is just one of the 9 different classes, in this example they go from ClassType1 to ClassType9)
But that doesn't work, I get these two warnings:
Property with 'retain (or strong)' attribute must be of object type.
Pointer to non-const type 'id' with no explicit ownership.
My question is, can something like this be achieved, or do I need to create an instance of each class just in case it needs to be used?

Gabriele gave already a correct answer. However,
if all the classes have identical methods and properties, you should consider to
make all classes inherit from a common superclass, and declare the property as
#property (nonatomic, strong) SuperClass * currentObj;
OR define a #protocol which comprises the common methods/properties, make all
classes conform to that protocol, and declare the property as
#property (nonatomic, strong) id <YourProtocol> currentObj;
The advantage in both cases is that the compiler can do more/better error checking when
the property is assigned or used.

id is already a pointer.
Change
#property (nonatomic, strong) id * currentObj;
to
#property (nonatomic, strong) id currentObj;
Moreover, please use capitalized names for classes.

Related

difference between a variable with and without an underscore in objective-c [duplicate]

This question already has answers here:
How does an underscore in front of a variable in a cocoa objective-c class work?
(9 answers)
Closed 9 years ago.
In the tutorial i am following, it creates a property of an array like so
#property (nonatomic, retain) NSMutableArray *entries;
And in the implementation file and defines it defines it as...
entries = [[NSMutableArray alloc] init];
However in my program, defining like that gives me an error
"Use of undeclared identifier 'entries'; did you mean '_entries'?"
Does this affect my program?
In simple:
#property (nonatomic, retain) NSMutableArray *entries;
creates the following code for you:
An ivar called _entries and two methods
- (void)setEntries:(NSMutableArray *)entries;
- (NSMutableArray *)entries;
If you want to give the ivar a different name (e. g. entries without underscore) you have to synthesize them. But you hardly ever need the actual, just use your properties like self.entries.
The rare cases where you actually want the ivar is when you want to override the setter and getter method
- (void)setEntries:(NSMutableArray *)entries
{
_entries = entries;
// do more stuff
}
When you declare property compilator create private variable which you can access with underscore (_entries) and compilator also create setter (if you do not specify readonly) and getter. You can call getter in two ways:
[self entries] or self.entries
When you declare property you should access in it two ways:
_entries - You access your private variable directly (can be use just inside the class)
self.entries - You can access this property view setter/getter it's safe way because this method manage way how to access it (release, retain, copy, etc.)
#property (nonatomic, retain) NSMutableArray *entries; is nothing but an instance variable of name _entries. (or any other name, that you can specify while doing the synthesize)
When you do #synthesize entries, two accessor methods (setter and getter) are created for you
- (void)setEntries:(NSMutableArray *)entries;
- (NSMutableArray *)entries;
If you access it directly as _entries, then it is just changing the value of the variable.
But if you say self.entries, the accessor methods are called. The accessor methods are made according to what property type you specified, strong (or retain) copy assign atomic, say assign will just copy the value to the variable, atomic makes sure that if setter and getter are called together from different threads, getter always gets the value either prior to the start of setter or after the completion of setter.

Possible to set multiple parent entities for Core Data NSManagedObject?

I have created the following example Core Data NSManagedObject subclasses:
PBCommentableObject : NSManagedObject // to allow comments on object
#property (nonatomic, retain) NSSet *pBcomments; // unordered set of PBComment objects
PBComment : PBCommentableObject // to allow comments on a comment
#property (nonatomic, retain) PBCommentableObject *target;
PBList : PBCommentableObject // to allow comments on a list
#property (nonatomic, retain) NSOrderedSet *pBorderedItems; // ordered set of PBListableObject objects
PBString : PBListableObject // to allow strings to be added to lists
#property (nonatomic, retain) NSString *pBtext;
PBListableObject : ???? // I'd like both PBList and PBString to be PBListableObjects
#property (nonatomic, retain) PBList *pBlist;
The problem I am having is that I would like the following behavior:
Lists (PBList) that can hold an ordered list of strings (PBString) or other lists (PBList).
Allow comments (PBComment) on lists (PBList) and other comments (PBComment) but not strings (PBString)
Is this possible to do? I am currently trying to build the Core Data model via the visual interface in Xcode; and while I could conceive of using categories, I don't know how I would do so without Xcode spitting out a warning when I fail to define a relationship via the visual editor.
I think you are stretching the idiom of inheritance. All this "listable" and "commentable" results in quite unreadable complexity.
The validation of allowing or disallowing comments, lists or what have you, can be modeled with simply using (boolean) attributes and relationships. Try to think of only concrete objects such as "Comment" or "String" and model the lists with the attribute sets.

Guidelines for using properties vs methods

I often have a hard time deciding if certain data should be exposed through a property or a method. You can say "use properties for object state", but that's not very satisfying. Take this example for instance:
- (NSString *)stringOne
{
return _stringOne;
}
- (NSString *)stringTwo
{
return _stringTwo;
}
- (NSString *)mainString
{
return [_stringOne length] > 0 ? _stringOne : _stringTwo;
}
It's clear that stringOne and stringTwo should be properties because they are clearly object state. It's not clear, however, if mainString should be a property. To the end user mainString acts like state. To your object, mainString is not state.
This example is contrived but hopefully you get the idea. Yes, properties are nothing more than a convenient way to create getters and setters but they also communicate something to the user. Does anyone have decent guidelines for deciding when to use a property vs a method.
Hiding the split between "true" state (string1 and string2 in your example) and "dynamic" state (mainString) is, I would say, exactly what properties are for.
The canonical example would probably be an object that represents a person, with given and family names as "state". A third piece of state, "full name" can be presented from those two pieces, but clients have absolutely no reason to know whether the full name is constructed on demand, or is created and stored when both of its pieces are set. It simply doesn't matter.
Properties are an interface -- what bits of data does this class provide to its clients (and what can the clients configure about the class)? The implementation of each property is encapsulated and does not affect its status as a property.
In ObjC, of course, we use methods to access properties. Other methods, however, represent actions that an object can take, possibly being passed some piece of data to operate on.
Another consideration to take into account : do you want to store the value of the property ? (via NSCoding or in Core Data for example)
I guess you NEED to create properties for things you need to "save" (in "encodeWithCoder" for instance. Deciding what you want to put in encodeWithCoder could help you decide which way you want to define things).
For things you don't need to save and can recalculate easily, you have the choice between a method and a readonly property (which is equivalent under the hood : a readonly property only creates a getter accessor method, and does not have an instance variable to back it). So that's more a question of style.
Speaking of style, if you use dot notation for properties only (as I do), you'd maybe wonder :
- do I want to access the full name as foo.fullName, and not make a difference with other properties like foo.firstName and foo.lastName ?
- or do you want to make a difference by accessing the full name with [foo fullName], showing to the world that this is calculated ?
I created an app for following stock quotes, and the model was inspired from an example in the Big Nerd Ranch book about Objective C (good read, by the way).
Here is how properties and methods are defined :
// properties
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *symbol;
#property (nonatomic, copy) NSString *currency;
#property (nonatomic, copy) NSString *market;
#property (nonatomic) int numberOfShares;
#property (nonatomic) double purchaseSharePrice;
#property (nonatomic) double currentSharePrice;
// Stock Calculation methods
- (double)costInLocalCurrency; // purchaseSharePrice * numberOfShares
- (double)valueInLocalCurrency; // currentSharePrice * numberOfShares
- (double)gainOrLossInLocalCurrency // valueInLocalCurrency - costInLocalCurrency
You can see that they are clearly distinguished.
The BNR does not use dot notation at all in their book, so it would all look the same : [foo currentSharePrice] or [foo valueInLocalCurrency], but as I use dot notation for properties, I would make a difference in style between foo.currentSharePrice and [foo valueInLocalCurrency].
Hope this is helpful.
By design, you should always respect the end user - if you think it's object state for the user of your class (which it apparently is), then go ahead and make a property out of it.

Semantic Issue: Property's synthesized getter follows Cocoa naming convention for returning 'owned' objects

I'm currently using the iOS 5 SDK trying to develop my app.
I'm trying to make an NSString a property, and then to synthesize it in the .m file (I have done this before with no issues). Now, I came across this: "Semantic Issue: Property's synthesized getter follows Cocoa naming convention for returning 'owned' objects."
This is my code:
.h
#interface ViewController : UIViewController {
NSString *newTitle;
}
#property (strong, nonatomic) NSString *newTitle;
.m
#synthesize newTitle;
Does anyone have a clue how I could fix this?
Thanks!!
My guess is that the compiler version you’re using follows the memory management rules for declared properties, too — more specifically, for declared properties’ accessors:
You take ownership of an object if you create it using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy”.
A property named newTitle, when synthesised, yields a method called -newTitle, hence the warning/error. -newTitle is supposed to be a getter method for the newTitle property, however naming conventions state that a method whose name begins with new returns an object that’s owned by the caller, which is not the case of getter methods.
You can solve this by:
Renaming that property:
#property (strong, nonatomic) NSString *theNewTitle;
Keeping the property name and specifying a getter name that doesn’t begin with one of the special method name prefixes:
#property (strong, nonatomic, getter=theNewTitle) NSString *newTitle;
Keeping both the property name and the getter name, and telling the compiler that, even though the getter name starts with new, it belongs to the none method family as opposed to the new method family:
#ifndef __has_attribute
#define __has_attribute(x) 0 // Compatibility with non-clang compilers
#endif
#if __has_attribute(objc_method_family)
#define BV_OBJC_METHOD_FAMILY_NONE __attribute__((objc_method_family(none)))
#else
#define BV_OBJC_METHOD_FAMILY_NONE
#endif
#interface ViewController : UIViewController
#property (strong, nonatomic) NSString *newTitle;
- (NSString *)newTitle BV_OBJC_METHOD_FAMILY_NONE;
#end
Note that even though this solution allows you to keep newTitle as both the property name and the getter name, having a method called -newTitle that doesn’t return an object owned by the caller can be confusing for other people reading your code.
For the record, Apple have published Transitioning to ARC Release Notes, in which they state:
You cannot give a property a name that begins with new or copy.
They’ve already been notified that their statement is not quite accurate: the culprit is the getter method name, not the property name.
Edit 17 Jan 2015: I’ve just noticed a recent commit to Clang that suggests option 3 above (using objc_method_family(none)), including a fix-it, for the general case where a property name matches one of the special method family prefixes. Xcode will likely incorporate this change eventually.
Unacceptable Object Names
newButton
copyLabel
allocTitle
Acceptable Object Names
neueButton
mCopyLabel
_allocTitle
#arc #auto-synthesized #xcode-4.6.1
** EDIT **
Apparently you can't use mutableCopy either.
The name of the member starting with new is what triggers the warning. Change the name to editedTitle and the warning will go away. I was unable to find documentation confirming this but through testing was able to determine that member variables that begin with 'new' aggravate the compiler.
ARC does not allow to use "New...." in property name. but you can use "newTitle" by changing getter name.
#property (nonatomic, strong, getter=theNewTitle) NSString *newTitle;
It doesn't look like what Bavarious was suggesting was what you wanted to do. All you want to do is declare an instance variable NewTitle and then synthesize the property. We used to have to declare the instance variable and property. No more.
Now, I believe the right way of doing this is the following:
.h
#interface ViewController : UIViewController
#property (nonatomic, strong) NSString *newTitle;
.m
#synthesize newTitle = _newTitle; // Use instance variable _newTitle for storage
The instance variable for the property newTitle is synthesized. You don't want your instance variable to be the same as your property - too easy to make mistakes.
See Example: Declaring Properties and Synthesizing Accessors
In CoreData if you use "new..." in attribute (compile normally) it will crash randomly with a "bad access" exception.
There is no crash log and the line shown with the "All Exceptions Breakpoint" will not help you at all.
Writing a setter manually with the name same as the property's removed this warning.
NS_RETURNS_NOT_RETAINED is used to solve the naming problem.
#property (nonatomic, copy) NSString *newTitle NS_RETURNS_NOT_RETAINED;
We can find its definition as follows:
#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
The 'ns_returns_not_retained' attribute is the complement of 'ns_returns_retained'. Where a function or method may appear to obey the Cocoa conventions and return a retained Cocoa object, this attribute can be used to indicate that the object reference returned should not be considered as an "owning" reference being returned to the caller. The Foundation framework defines a macro NS_RETURNS_NOT_RETAINED that is functionally equivalent to the one shown below.
Besides the issue that you should/can't use "new" in front of you property names, let say one more thing: Try to avoid "new" in front of names in general. "New" is dependent on time. Currently it is new for you, but some time later you maybe want to implement something new again. So using "new" in names is always bad. Try to think this way: In the programming world, "new" is always creating something: a new instance of something.
In your case when you want to assign a different title then the current name your property titleReplacement.
One more thing: Try to name functions and methods with the verb first, like setSomething or getSomething.
But in properties try to name the object first, like heightMinimum, heightMaximum, etc. -> when you use your inspector when you are coding, you always looking for objects. Try it out. ;-)
try this:-
#property (nonatomic,retain) NSString *newTitle;

c-style member vars in obj-c

I've noticed that I cannot use the #property / #synthesize for member vars that are arrays in obj-c. For instance the member var int mVar[5] cannot use the #property/#synthesize.
However, I've noticed that I can set these vars simply by not using self.mVar[n] but instead using mVar[n].
Can someone explain why this works, if this is good or terrible practice, and what alternative I should use if it is not good practice?
Properties are syntactic sugar for set/get-style methods. Passing arrays in as parameters and out as return values via these methods is fraught with semantic and performance problems, so they probably just put them in the too-hard basket and deliberately excluded them.
As regular data members, arrays don't exhibit these difficulties because you are accessing them directly rather than copying them in and out via methods.
If you want to make the contents of an array accessible as a property (which you should only need to do if you want to make the contents public), you can expose them as:
#property (readonly) int *vars;
#property (readonly) int numVars;
Or you could do the Objective-C thing:
#property (nonatomic, retain) NSArray *vars;
But then you would have to create lots of NSNumber objects (ick).