Objective-C generics - is there a way to make the generic match the class (in cases of inheritance) - objective-c

I have ClassA and ClassB, and I'd like to make ClassB inherit from ClassA to streamline my code. The problem is that almost everything is shared except that for ClassA I have a generic array like so:
#property NSMutableArray<ClassADataType*> objectsArray;
whereas for ClassB I have a generic array:
#property NSMutableArray<ClassBDataType*>
Similarly for ClassA I have a property of a single class instance like so:
#property ClassADataType* object
and for ClassB I have a property like so
#property ClassBDataType* object
ClassBDataType inherits from ClassADataType, and similarly I would like to make ClassB inherit from ClassA. Is there a way to do this, basically overriding a class property of the class from which a class inherits?

No, this would violate Liskov Substitution, particularly because these are mutable properties as written. For example:
ClassA *a = [ClassB new]; // Legal and proper because B is an A.
a.object = [ClassADataType new]; // "Legal," but completely broken.
(If they were immutable properties, in principle this kind of feature could exist without creating these problems, but ObjC doesn't provide the feature even in that limited case, and it's hard to prove a property is always readonly in ObjC.)
In most cases the right answer is not to use inheritance. Generally it is better to handle shared code through composition (helper objects) rather than class hierarchies. This is especially true since you say this is "to streamline my code." You should never create inheritance unless you can say "in all ways, a B is a more specific kind of A." It's not good enough to say "they have a lot of code in common."
If you really do need to use inheritance, the common technique is to add another property to B that downcasts.
#property (readonly) ClassBDataType* classBObject;
- (ClassBDataType *) classBObject {
return (ClassBDataType *)self.classAObject;
}
It is very important in this case that these properties be readonly to the outside world, or else you can get the inconsistencies mentioned above.

In addition to the answer by Rob. I have had similar cases and I think there could be a case for inheritance, however if B is not a direct descendant from A I have found the best pattern is an abstract class baseAB that both A and B inherits from and that has all the shared code.
For the typed array property then each subclass can have it's own, but that is probably not so good as then a lot of code cannot move to the base class. Depends on how central this array is to the class.
The option then could be to put a generic array property in the base class with a shared ancestor of the ClassADataType and ClassBDataType, but that may defeat the idea of typing the array.
Or you could skip the generics for the array, make it an iVar of the base class and provide custom typed methods in the subclassess to set and get values and do the type checking.

Related

What is the benefit of using associated objects vs static object defined in the category implementation file?

The problem is I don't see the benefit of using associated objects vs static objects defined in the category implementation file with getter/setter methods.
I was thinking about defining the getters and setters in the header file of the category. Like this:
#interface NSObject (test_static)
- (id)getStaticObject;
- (void)setStaticObject:(id)a_static;
#end
and then to declare a static variable in the implementation file and implement getter/setter methods, like this:
static id test;
#implementation NSObject (test_static)
- (id)getStaticObject
{
return test;
}
- (void)setStaticObject:(id)a_static
{
test = a_static;
}
Why I shouldn't use this approach and use associated objects instead ?
Well, I guess I didn't get how properties work and how they've solved the fragile base class problem. Maybe it's related...
There is a huge difference. Associated objects is a way to simulate properties in a category.
Using a single static variable means you have a single, shared value used across all instances.
The choice is which to use depends on your goal. If you want an instance specific result from your two category methods, do not use a static variable - use associated objects. If you want the same object back from the two category methods regardless of the object instance, then use the static variable (and probably change your category methods to class methods instead of instance methods).

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.

instancetype vs class name for singleton?

From what I understand, instancetype declares to the compiler that the return type of the method is the same as the class receiving the message.
Traditionally I've always declared my singleton initializers with the class name explicitly set as the return type:
#interface MyClass : NSObject
+ (MyClass *)sharedInstance;
#end
Now I'm wondering if I should use instancetype instead, like so:
#interface MyClass : NSObject
+ (instancetype)sharedInstance;
#end
In the end the result is the same, I'm just wondering if there's a reason to use one or the other here?
instancetype is useful for situations involving inheritance. Consider you have class A which inherits from class B. A method in B which returns an instance of B may be declared previously as id, its override in A may return an instance of A - which is all good but the compiler has no clue. However by using instance type the compiler is informed that when called on an A instance that the method returns an A instance, and so can give better diagnostics, code completion, etc.
Now in your example you've used MyClass * rather than id, so you've already told the compiler the type. You also have a shared instance model (not a singleton model as you can other instances of MyClass), are you likely to define another class which inherits from MyClass and overrides the sharedInstance method? Probably not, but if you do instancetype may be of use, otherwise it gains nothing.
Constructor methods traditionally have returned id, allowing subclasses to use them too.
id, of course, means "any object at all". instancetype was introduced to give a little more type strictness when assigning the result of a constructor method.
It's only useful in case of subclassing. If that method will never be overridden, it's better to be as explicit as possible and use the actual class name.

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;

How to access #public instance variable from another class in Objective-C?

I know it's possible to define public instance variable with #public keyword.
However, Objective-C syntax does not allow accessing other class' variable.
What features should I expected from #public Ivar? Or how do I access other class' Ivars?
Objective-C, as a superset of C, definitely does allow the access of public instance variables from outside the class's implementation. Now, the reason you may have heard that it isn't allowed is that it is highly discouraged. In most cases, if you want to access an instance variable outside an implementation context, you should be using accessors and mutators (properties).
An Objective-C class really boils down to a plain-old C struct with an isa field (that's what makes it an object), where the public fields are accessible. Since when we are dealing with instances of classes, we are working a pointer to an object (special struct). Thus, we access public fields using ->.
Here's an example:
#interface SomebodyIsntEncapsulating : NSBadIdea {
#public
NSString *badIdea;
BOOL shouldntDoIt;
#protected
NSString *ahThatsBetterThankGod;
#private
NSString *sweetThanksNowEvenMySubclassesCantTouchMe;
}
Now, in some completely different context, we could have:
SomebodyIsntEncapsulating *whatOh = [[SomebodyIsntEncapsulating alloc]
initWithDanger:kDangerLevelEpicBraceYourself];
whatOh->badIdea = [#"I'm a public field. Make sure to retain or copy me!" copy];
NSLog(#"Please! Write some accessors and mutators!: %#", whatOh->badIdea);
I hope that helped you!
You can access it like using -> (member by pointer) operator like you normally access members of a c-structure (note that you always have a pointer to an object in obj-c):
...
#public
int a;
...
myObject->a = 1;
You are supposed to write accessor methods to do that. Object-oriented design implies that a class shouldn't care about internal structure of objects of another class.
That said, id is just a pointer, so you can do obj->ivar, provided you know what you're doing and there is no way to write a proper accessor method.