multiple custom objects with same properies - objective-c

i have 7 custom objects with the same properties, createDate and modifiedDate. can i create a method that accepts Object1 but actually takes all 7 objects?
right now, this works:
[self setCreateAndModifiedTimeWithEvent:((Object1 *) object2
WithCreateDate:[[eventsArray objectAtIndex:i] objectForKey:#"create_date"]
AndModifiedDate:[[eventsArray objectAtIndex:i] objectForKey:#"modified_date"]];
.h file
-(void) setCreateAndModifiedTimeWithEvent:(Object1 *)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp;
.m file
-(void) setCreateAndModifiedTimeWithEvent:(Object1 *)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp
{
object.A = #"Hello,";
object.B = #"World";
}
this would cut back on good chuck of lines of code.
i know you can do this sort of thing with UIView and its subclasses. say i have a
UITextField myTextField.
i can do
((UIScrollView *)myTextField).tag = 2;
is there anything inherently bad about typecasting my objects like this or is it acceptable?

Like Joe said, you'd be better off with something like this:
#interface DatedObject : NSObject
#property NSDate *createDate;
#property NSDate *modifiedDate;
#end
#implementation DatedObject
#synthesize createDate;
#synthesize modifiedDate;
#end
Then have each of the 7 classes inherit from the DatedObject base class. Inheritance is a fundamental part of Object Oriented Programming, and you should learn to use it (wisely).
Then your method can be:
-(void) setCreateAndModifiedTimeWithEvent:(DatedObject *)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp;
You could also do this with a protocol, but the nice thing about using a base class that the other classes inherit from is that you only have to implement this functionality in one place. If the 7 classes don't all currently inherit from the same base class (which would end up being the superclass of DatedObject), a protocol is probably the way to go. In that case, you can declare your method like this:
-(void) setCreateAndModifiedTimeWithEvent:(id<DatedObjectProtocol>)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp;
One of the big advantages to these two approaches over what you've posted in your question is that you get more help from the compiler in catching places where your code sends a message to an object that doesn't respond to it.

Andrew's answer is correct.
But, if for some reason you don't want to create a common base class or a protocol, you could always set the type of the method parameter to id, like this:
-(void) setCreateAndModifiedTimeWithEvent:(id)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp;
Parameters of type id don't do any type checking at compile time (like the values in an NSArray) so you can call any method you want on them without generating compiler warnings (this is obviously quite dangerous if you aren't careful).
You can't use dot notation on id variable without casting, but it's better to cast from an id to a concrete type than to cast from a different unrelated type.
It doesn't actually make any difference except to your code readability though.

Related

Key-Value Coding with a key of 'description'

I am using Key-Value Coding to simplify updating instances of a model class:
#interface NewsItem : NSObject
{
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *description;
#property (nonatomic, copy) NSString *link;
#property (nonatomic, copy) NSString *date;
using:
SEL selectorName = NSSelectorFromString(elementName);
if ([self.newsItem respondsToSelector:selectorName])
{
NSString *sanitisedElement = [self sanitiseElement:self.currentElementData];
[self.newsItem setValue:sanitisedElement forKey:elementName];
}
This works well but the 'description' property doesn't 'smell' right to me as it has overridden the base NSObject description getter (+ (NSString *)description). If the description getter is invoked now it will return irrelevant information when the caller would be expecting a description of the class.
Is it possible to safely proceed with Key-Value Coding for this class (given that I am bound to these property names by the external data source)? Or would it be wise to change the property names and manually check keys/set values instead?
You could override description in your class. This method is usually used only for debugging
and no caller can expect a specific output of that method.
But I see more general problems in your code. It is only checked that a method with the
given name exists. This does not imply that this method corresponds to a property, and even then, it does not imply that there is a setter for that property.
For example, every NSObject responds to the selector "init", so if the external
data source sends that key as "elementName", your code would immediately crash.
Therefore, an explicit list of "known keys" is needed. But then you can as well
use a mapping (NSDictionary) from external element names to internal properties
to avoid any conflicts.
I think that you are confusing methods with properties, and you are making things more complicated that how they are.
Is enough that, given an elementName that contains directly the setter name (i.e.: setDate), you invoke the selector passing that argument the object argument:
SEL selectorName = NSSelectorFromString(elementName); // elementName something like "setDate"
if ([self.newsItem respondsToSelector:selectorName])
{
[self.newsItem performSelector: selectorName withObject: sanitisedElement];
}
As for the description method, it has overridden NSObject's description, so you have two choices: name it in another way, or leave it like it is, and invoke it on super when you need the object description, with the help of Objective-C runtime:
struct objc_super superclass= { self.newItem, [self.newItem superclass] };
NSString* desc= objc_msgSendSuper(&superclass, #selector(description));
You can always override inherited methods.
By creating a property whose getter is the same as the signature of An inherited method, you are overriding it.
Is it bad? Yes if your implementation is not useful for debugging.
As best practice for KVC and KVO purposes it is a good idea to avoid potentially clashing with common inherited methods properties and ivars.
The common approach to this is to make longer property and method names and to make them more likely to be unique. One common way is by prefixing all yours with an abbreviation common to your class or framework or code.
Using something commonly used by Apple is likely to bite you in a rare and hard to debug way.
It's especially a bad idea to do this when core data is involved.
Don't be reluctant to make things longer. Code completion will type for you. Plus, a nice side effect of class specific prefixing is pseudo not only the pseudo namespace but that your class specific properties, variables, constants and methods will bubble up first in code completion.

Method parameter wihout type?

What did I do here? Can method parameters be typeless?
In a recent project which works fine, the App is in the store already - no issues so far, I did the following in a .h file:
#property (strong, nonatomic) NSManagedObject *myPerson;
- (HKPersonPicker*) initWithPerson:person;
- (HKPersonPicker*) initWithPerson:person delegate:(id <HKPersonPickerDelegate>)delegate;
I meant to do it this way but did not:
- (HKPersonPicker*) initWithPerson:(NSManagedObject*)person;
- (HKPersonPicker*) initWithPerson:(NSManagedObject*)person delegate:(id <HKPersonPickerDelegate>)delegate;
The corresponding part of the .m file:
- (HKPersonPicker*) initWithPerson:person
{
self = [super init];
if(self){
self.myPerson = person;
}
return (self);
}
- (HKPersonPicker*) initWithPerson:person delegate:(id <HKPersonPickerDelegate>)delegate
{
self = [self initWithPerson:person];
if(self){
self.delegate = delegate;
}
return (self);
}
As you can see I did not do anything special with this person object, just assigned it to the property myPerson. As I did not call any of the object's methods or accessed its data, the compiler did not need to know anything about that object. But what is it from the compiler's point of ivew? Type id? Just something? Is there any default type?
As you see, I do not have any real problem. I am just curious. Hope this question does not break any SO rule.
With C the default type is int, but with Objective-C it's id.
Missing type declarations in methods default to id. IIRC, you can see a fair number of methods without return types in Apple's runtime library.
There is no definitive problem with what you are doing, but its not really kosher at the same time. You should still have a type declaration for the sake of clarity, and maintaining good and consistent Cocoa-like code styling.
So it should really be like:
- (GSPersonPicker*) initWithPerson:(id)person;
And you should really change the property declaration:
#property (strong, nonatomic) id *myPerson;
If that is not changed, then your code is confusing. You KNOW the type that will be coming in. So let the compiler help you with meaningful warnings/errors by using types. You should also probably be using the type 'HKPerson' or whatever you have named your entity, so the compiler doesn't think its ok for you to pass in an 'HKPlace' (they will both be of type 'id' and 'NSManagedObject', which does you no favors)
More importantly, you should not be using the dynamic type (id) unless you have a reason. The compiler is there to help you. Errors and warnings are your friend, they tell you that you messed up, not the computer. When you use 'id', the compiler just goes, Oh, anything can go in here!!! And it will not detect an error where you sent that method a type that will break everything.
Now lets say that you are going to use polymorphism. IE, Lets declare a generic protocol for multiple classes to adhere to, which defines our person:
#protocol GSPerson
-(NSUInteger)age;
#end
So now lets define a couple classes, and have them subscribe to the protocol (the GSPerson thats between carrots markdown is killing me atm lol):
#import "GSPerson.h"
#interface GSSpecialPerson <GSPerson>
// code
#end
#import "GSPerson.h"
#interface GSWeirdPerson <GSPerson>
// code
#end
Then lets redefine our method signature to adhere to the protocol:
- (GSPersonPicker*) initWithPerson:(id<GSPerson>)person;
And our property declaration:
#property (strong, nonatomic) id <GSPerson> *myPerson;
Now the compiler knows that anything i pass into that method should conform to the GSPerson protocol I defined above (ie they need a method that returns the persons age). If i try to pass anything else in, it will throw compiler warnings, WHICH IS GOOD.
Even better, it will throw warnings on your polymorphic classes if they are missing their required methods.

Clarification on Asterisks and Underscores in Cocoa Syntax

I recently picked up the BigNerdRanch book on Cocoa for Mac OSX and am looking for a good explanation around the use of asterisks * and underscores _ that seem to be inconsistently used throughout the language. Some examples:
These appear to be functionally equivalent:
NSString* myString;
NSString *myString;
Sometimes new variables get an underscore, while others dont:
NSString _myString;
NSString myString;
And sometimes it gets all crazy:
NSString *myString;
NSString *_myString;
I've also seen variations with asterisks in methods:
- (void)speechSynthesizer:(NSSpeechSynthesizer *)sender
willSpeakWord:(NSRange)characterRange
ofString:(NSString *)string;
So what is the functional use of the asterisk or the underscore, when should you use (or not use) either, and when should they be used in combination?
The * indicate a pointer, which all Objective-C objects are. (You pass around pointers to these objects in memory). At a basic level these are normal C pointers. If I remember correctly You could access some data in an Objective-C object by going object->data, just like you do with pointers to C structs.
The _ is a Cocoa (and some other languages) convention, meaning "a piece of data that should be considered private to this object".
Objective-C has a #private declaration, but it's also a relatively new addition to the language - if your code is more than 2 or 3 years old (or targeting much older versions of OS X) it might not use #private
Because of this initial lacking of language infrastructure, the _ is (often) used by the Cocoa community to mark "Hey, you probably shouldn't set or read this directly, please".
So:
When dealing with Objective-C classes you always need the * to follow the class name (like NSString), because they are always pointers. I'm confused about your NSString somestring line in your code - either that'll generate a complier warning or will crash when you try to use it
The _ indicates private data. You would do something like NSString* _name in a #interface section of your Objective-C class. You would use _name by itself if you were calling or operating on that data in a method in your class.
So say you created a Student class:
// Student.h
#interface Student : NSObject {
NSString* _name;
}
- (NSString*) name_as_caps;
#end
// Student.m
#implementation Student
- (NSString*) name_as_caps {
return [_name uppercase];
}
Here we declare a class with a "private" data member: _name. Our Student class needs to return this capitalized for some reason, so we created a method to do that, where we use _name and call the uppercase method on it.
We needed to refer to the type (or class name) or _name a few times here: once, to declare the variable. For name_as_caps we needed to say: this method returns a pointer to an NSString object, thus we used NSString *.
As an addendum to Ryan's answer, when you see something like
-(void)speechSynthesizer:(NSSpeechSynthesizer *)sender willSpeakWord:(NSRange)character
RangeofString:(NSString *)string;
the things like (NSSpeechSynthesizer *)sender just state the type of the argument - in this case NSSpeechSynthesizer*

Do Objective-C Category names do anything?

A class can be extended in Objective C using a category such as:
#interface NSString (CategoryName)
-(NSString *)myFabulousAddition; // a fabulous additional method
#end
/////////////////////////////
#implementation NSString (CategoryName)
-(NSString *)myFabulousAddition {
// do something fabulous...
}
#end
In this small example, I would be adding the method myFabulousAddition to NSString. I could then call it by [anNSString myFabulousAddition] just as if it were part of the NSString set of methods. Great and useful.
In the Apple documents regarding Categories, the docs state:
There’s no limit to the number of
categories that you can add to a
class, but each category name must be
different, and each should declare and
define a different set of methods.
What if you have something like this:
#interface NSString (CategoryName)
-(NSString *)myFabulousAddition; // a fabulous additional method
#end
#interface NSString (ANOTHERCategoryName)
-(NSString *)myFabulousAddition; // a DIFFERENT fabulous additional method
// BUT with same name as the other category
#end
/////////////////////////////
#implementation NSString (CategoryName)
-(NSString *)myFabulousAddition {
// do something fabulous...
}
#end
#implementation NSString (ANOTHERCategoryName)
-(NSString *)myFabulousAddition {
// do something equally fabulous, but DIFFERENT...
}
#end
The lack of a name in the parenthesis indicates that the form is an extension to the class, like so:
#interface MyObject () // No name -- an extension vs category to MyObject
- (void)setNumber:(NSNumber *)newNumber;
#end
Does the category name have any meaning to the compiler or linker? Is the category name part of the method signature in anyway or is it part of a primitive namespace? If the category name is meaningless, how do you know if you are about to stomp on another method and get undefined behavior?
The way to avoid stomping on methods is to prefix your category method names, like this:
#interface NSString (MyCompanyCategoryName)
- (NSString *)MYCO_fabulousAddition;
#end
If you get a collision of method names from different categories, then which one 'wins' at run time is completely undefined.
The name of a category is almost entirely useless, with the exception being that the nameless category (i.e. ()) is reserved for class extensions. Methods from class extensions are supposed to be implemented in the class' main #implementation.
The category name doesn't mean anything special, it's just an identifier. Unless the linker (or runtime loader) decides to give you a warning, there is no way to tell that multiple categories are defining the same method.
The behavior is (largely) unpredictable - one of the categories will win out, but you can't tell which one. Also, I think it's well possible you will start out with one implementation and end up with another one (if the second category is loaded after the first).
It certainly acts as an identifier, from the programmer's point of view. In the compiler point of view category methods are simply added as an extension of the class ( from which it is extending), regardless of the name.
And yes you can add categories of the same class with the same identifiers, even with same functions. But you definitely can't override any function because categories are just part of the class once you define them ( Just like you can't override a function of a class from within that class ).
As they are being added at runtime, they don't raise any error and only at runtime compiler selects the function, which is totally unpredictable.
i believe that they don't have any meaning. You don't really use them in your code ... Since they are categories and ... the semantic of a category ... is just to categorize something, i think this is somewhat logical ...
I would say they just simply gather the methods ...
On the other hand your question is very valid ... You DON'T KNOW if you override a method. If you are in the same project then the compiler issues a warning (or an error ? i don't remember), however if you are overriding a method from a library, then .. you are out of luck ...

NSMutableArray with only a particular type of objects

is it possible to specify that a NSMutableArray can only contain a certain type of objects.
For example, if I want to store only this kind of objects :
#interface MyObject : NSObject {
UInt8 value;
}
In order to be able to use the instance variable like this :
- (void)myMethod:(NSMutableArray *)myArray{
for (id myObject in myArray){
[self otherMethod:myObject.value];
}
}
because I'm getting this error :
request for member 'value' in something not a structure or union
Thank you for your help
It sounds like you're coming from a Java/C# type background where limits can be imposed on collections.
Collections in Cocoa don't follow that pattern. There is no way to set a restriction on what type of objects can be inserted (unless you write a wrapper class that enforces this).
Objective-C, by design, follows the "if it walks like a duck and it quacks like a duck, then it most probably is a duck" philosophy. That is to say that rather than checking whether an object is a particular type, you should be checking whether it can do what you want it to do regardless of its type.
You can do this using respondsToSelector:.
Finally, your problem isn't actually related to the fact that the array has no restrictions. Your object doesn't appear to declare the instance variable value as a property, or expose any accessor methods for it.
This is why you're seeing the error when you try myObject.value. That syntax in Objective-C is how you access properties.
The default scope for instance variables in Objective-C is #protected, which means anything outside your class can't access them without going through an accessor method of some kind.
You need to declare and define the methods - (UInt8)value and - (void)setValue:(UInt8)aValue and use them.
Alternatively, you could declare it as a property.
You are getting that error, because for as far as Objective-C is concerned, myObject is of the non-type id, which doesn't support the value property. To make Objective-C aware of the fact it's always dealing with a MyObject in this loop, you'll have to tell it the myObject object is an instance of MyObject.
for (MyObject *myObject in myArray) {
Also, you have to make sure the value ivar is accessible using dot-notation by implementing getter and setter methods for it. You can do this yourself by implementing -value and -setValue:, or you can use #property and #synthesize to let Objective-C do this.
Objective-C doesn't work like that. You need to use [myObject value] (which will work irrespective of the kind of object, as long as it responds to -[value]. If you only want one type of objects in it, insert only that type of objects.
You would have to write a wrapper-class for the NSMutableArray, see for example this question.
Subclass NSMutableArray and override methods that mediate the addition of objects to the array. You would check the object type in these overridden methods, only calling [super addObject:xyz] if the type is accepted.
maybe you can use protocol:
#protocol Person <NSObject>
#end
#interface Person : NSObject <Person>
#end
to use:
NSArray<Person>* personArray;