Auto conversion type - Objective C - objective-c

I am new to Objective-C and I would like to know if there is any way to implicitly convert an object.
By implicitly, I mean, for example, writing something like this :
MyColorClass *color = [[MyColorClass alloc] init];
SomeStuffUsingUIColor(color);
Instead of this :
MyColorClass *color = [[MyColorClass alloc] init];
SomeStuffUsingUIColor([color toUIColor]);
I know that there is no way to overload casting operators (in Objective-C), but maybe there is a specific solution for this problem.

There's often no need to convert the object to a new type. Just implement the same methods that UIColor does, so that MyColorClass responds to the same messages. This isn't always enough -- for example, if MyColorClass isn't a UIColor subclass, it won't get any methods added to UIColor via a category. If you need that, it's best to derive MyColorClass from UIColor so that every instance of the former is an instance of the latter.

Usually, you want to create a category for this kind of things, e.g.
#interface UIColor (MyExtensions)
- (void)doSomethingUsingColor
#end
#implementation UIColor (MyExtensions)
- (void)doSomethingUsingColor {
//do something
}
#end
You can see some examples in NSString+UIStringDrawing.h category.
Also note that if you want to do something with a C struct, you would usually declare a function, e.g.
typedef struct {
int x;
int y;
} MyPoint;
void doSomethingWithPoint(MyPoint point) {
//do something
}
You can see examples in the API, for example: NSStringFromCGPoint.

Related

How to build a strong type container in Obj-C?

I'm building a class XXTreeNode:
#interface XXTreeNode : NSObject<XXSearching>
#property XXTreeNode *parent;
#property NSMutableArray *children;
#property id data; // problem here
#property(readonly) int count;
-(XXTreeNode*)initWithData: (id)data;
-(bool)addChild: (XXTreeNode*)child;
-(bool)removeSelf;
-(NSArray*)searchChildren: (id)content; // problem here
-(XXTreeNode*)searchChildrenFirst: (id)content; // problem here
#end
I want this class be generic -- I can store any types in 'data' field. In C#, I can do this easily with
class Node<T>
then I can create such class with any type I want:
Node<String> a = new Node<String>();
Node<int> b = new Node<int>();
But how to do such thing in Objective-C?
BTW: I know there is a 'id' type and you can see I already declare the fields I want to be generic as 'id', but 'id' is not suitable for simple types like NSInteger or unichar.
but id is not suitable for simple types like NSInteger or unichar.
That's what NSValue (docs) and its NSNumber subclass (docs) have been invented for.
id works fine for primitive types if you box them in NSValue (for structs) or NSNumber (for integral and float types). I have to recommend against using Objective-C generics, it depends on macros, and makes the code confusing.
Unfortunately you won't get type checking if you use simple id values. But keep in mind that generics (real ones in languages that support them) could be thought of as just a way to auto-generate custom subclasses tailored to the particular types in question. You can always write those classes yourself, e.g.
#interface IntNode : Node
#property int intData;
#end
#interface Node (IntSearching)
- (NSArray *)searchChildrenForInt:(int)anInt;
-(XXTreeNode*)searchChildrenForFirstInt:(int)anInt;
#end
You could implement it something like this:
#implementation IntNode
- (int)intData { return [_data intValue]; }
- (void)setIntData:(int)anInt { self.data = #(anInt); }
#end
#implementation Node (IntSearching)
- (NSArray *)searchChildrenForInt:(int)anInt {
return [self searchChildren:#(anInt)];
}
-(XXTreeNode*)searchChildrenForFirstInt:(int)anInt {
return [self searchChildrenFirst:#(anInt)];
}
Tomer Shiri created exactly this, only a couple of weeks ago so it is still quite new, might be worth checking out. (https://github.com/tomersh/Objective-C-Generics)
If you want to store numbers, you will need to use NSNumber which is a wrapper for numeric data-types

Does Objective-C have an equivalent to java annotations?

Does Objective-C have an equivalent to java annotations?
What's I'm trying to do is create a property and be able to somehow access some metadata about it.
I want to be able to determine what type of classes should go in my array so I'd like to annotate it somehow to say so. Then later be able to access that annotation via something like the runtime library where I can access lists of properties and their names.
//Put some sort of annotation giving a class name.
#property (strong) NSArray *myArray;
You said:
I want to be able to determine what type of classes should go in my array so I'd like to annotate it somehow to say so. Then later be able to access that annotation via something like the runtime library where I can access lists of properties and their names.
There are a few ways to do this sort of thing in Objective-C. Apple's frameworks do this sort of thing by adding a class method that returns the required information. Examples: dependent keys in KVO, +[CALayer needsDisplayForKey:] and related methods.
So, let's create a class method that returns an array of classes that can go into your container property, given the property name. First, we'll add a category to NSObject to implement a generic version of the method:
#interface NSObject (allowedClassesForContainerProperty)
+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name;
#end
#implementation NSObject (allowedClassesForContainerProperty)
+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name {
if (class_getProperty(self, name.UTF8String)) {
return #[ [NSObject class] ];
} else {
[NSException raise:NSInvalidArgumentException
format:#"%s called for non-existent property %#", __func__, name];
abort();
}
}
#end
As you can see, this default version of the method doesn't do anything particularly useful. But adding it to NSObject means we can send the message to any class without worrying about whether that class implements the method.
To make the message return something useful, we override it in our own classes. For example:
#implementation MyViewController
+ (NSArray *)allowedClassesForContainerPropertyWithName:(NSString *)name {
if ([name isEqualToString:#"myArray"]) {
return #[ [UIButton class], [UIImageView class] ];
} else {
return [super allowedClassesForContainerPropertyWithName:name];
}
}
...
We can use it like this:
SomeViewController *vc = ...;
SomeObject *object = ...;
if ([[vc.class allowedClassesForContainerPropertyWithName:#"bucket"] containsObject:object.class]) {
[vc.bucket addObject:object];
} else {
// oops, not supposed to put object in vc.bucket
}
There is no native support of this functionality, but you may to take a look at following solution — https://github.com/epam/lib-obj-c-attr/ It is compile time implementation of attributes. Definition of attributes based on defines but not on comments as in other solutions like ObjectiveCAnnotate.
Objective C does not support generics like in Java but ofcourse the language is very flexible that you can accomplish almost anything with simple tricks and knowledge. To implement a generic like feature you could create a category on NSArray class and create your own method to initialize the array and then check to see if the object is really the type of the object you want.
I would write a simple category on NSArray to have such functionality. Say suppose, I want my array to hold objects of class MyClass only then my category would look like,
#interface NSArray(MyCategory)
#end
#implementation NSArray(MyCategory)
-(NSArray*)arrayWithMyClasses:(NSArray*)classes{
if([classes count] > 0){
NSMutableArray *array = [[NSMutableArray alloc] init];
for(id anObj in classes){
NSAssert([anObj isKindOfClass:[MyClass class]], #"My array supports only objetcts of type MyClass");
[array addObject:anObj];
}
return array;
}
return nil;
}
#end
Of course, there is some limitations to it. Since you have created your own category, you should use your own method to initialize and create your own array.
No, Objective-C has no annotation or generics support.
A way to implement such a thing would be to hack Clang to read comments and associate a metadata object to the original object. But, you would be tied to your hacked compiler.
NSString *v1 = [[NSString alloc] init];
// associate
static char key;
NSString *v2 = [[NSString alloc] init];
objc_setAssociatedObject (
v1,
&key,
v2,
OBJC_ASSOCIATION_RETAIN
);
// retrieve
NSString *associate = (NSString *)objc_getAssociatedObject(v1, &key);
Qualifying with a protocol wouldn't be much trouble, and you could test if the collection implements it, but along the way you would need to create a category for each type on the same collection. This would require a different collection at compile time using macros. Overly complicated.
#interface Tomato:NSObject #end
#implementation Tomato #end
#protocol TomatoNSArray <NSObject>
- (Tomato*)objectAtIndexedSubscript:(NSUInteger)index;
- (void)setObject:(Tomato*)tomato atIndexedSubscript:(NSUInteger)index;
#end
// here is the problem, you would need to create one of this for each type
#interface NSMutableArray (TomatoNSArray) <TomatoNSArray>
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
NSMutableArray<TomatoNSArray> *tomatoes = [[NSMutableArray alloc] initWithCapacity:2];
tomatoes[0] = [Tomato new];
tomatoes[1] = [NSObject new]; // warning: incompatible pointer types
}
}
Does Objective-C have an equivalent to java annotations?
Not exactly an equivalent, but there is, and it's better. In Objective-C, the compiler has to store some type and name information in the compiled code (because the language is highly dynamic, a lot of things happen at runtime as opposed to compile time), for example method names ("selectors"), method type signatures, data about properties, protocols, etc. The Objective-C runtime library then has access to this data. For example, you can get the list of properties an object has by writing
id object = // obtain an object somehow
unsigned count;
objc_property_t *props = class_copyPropertyList([object class], &count);
Or you can check what class an object belongs to:
if ([object isKindOfClass:[NSArray class]]) {
// do stuff
}
(Yes, part of the runtime library is itself wrapped into some methods of NSObject for convenience, others only have C function APIs.)
If you specifically want to store custom metadata about an object or a class, you can do that using associated references.
I expect it should be clear now, the answer is NO, not at the moment.
Some people found some alternatives which seem to work in their specific use cases.
But in general there is no comparable feature yet in objective-c. IMHO clang metadata seems to provide a good foundations for this, but as long as there is not support from Apple this will not help, as far as i understood it.
Btw. I guess it should be clear, but just to repeat for all: two changes are required to support annotations as provided in java.
The language need an extension the annotate e.g. methodes, properites, classes, ... in the source code.
A standard interface is required to access the annotated information. This can only provide by apple.
Most alternativ soltuions move the annotation information into runtime and define their own interface. The objective-c runtime provide a standard interface but only with some trick you can annotate properties and still the isse of runtime population.
The typical use case for suche a feature is an IOC container (in Java e.g. Spring) which use the annotated information to inject other objects.
I would suggest to open an feature requrest for Apple to support this.
The answer to your question is that Objective-C does not have a direct equivalent of annotations as found in Java/C#, and though as some have suggested you might be able to engineer something along the same lines it probably is either far too much work or won't pass muster.
To address your particular need see this answer which shows how to construct an array which holds objects of only one type; enforcement is dynamic and not static as with parametric types/generics, but that is what you'd be getting with your annotation so it probably matches your particular need in this case. HTH.
What you need maybe a metadata parser for Objective-C. I have used ObjectiveCAnnotate (compile time retrievable) and ROAnnotation(runtime retrievable).

Objective-C dynamic_cast?

Is there an Objective-C equivalent of C++'s dynamic_cast?
It can be faked using this:
MyClass *safeObject = [object isKindOfClass: [MyClass class]]
? (MyClass *)originalObject : nil;
But this is a lot of code to type, even if I don't need to type it often.
I am a bit rusty so this might not be quite right, but I believe the equivalent in C++ would be:
MyClass safeObject = dynamic_cast<MyClass>(orginalObject);
The context here is a block where the parameter is defined as a type of a more generic class, but in this block I "know" it's a specific subclass. Nevertheless, I don't want to just cast it blindly with (MyClass *)originalObject and ignore a theoretically possible error.
To be clear, while I'd love a dynamic_cast, I'd be happy with an alternate approach to safely handle this case as well.
If you're willing to use Objective-C++, you can write this pretty easily:
template<typename T> inline T* objc_cast(id from) {
if ([from isKindOfClass:[T class]]) {
return static_cast<T*>(from);
}
return nil;
}
This should behave exactly as dynamic_cast<> except for obj-c objects.
If you want to stick with vanilla Obj-C you can get similar behavior with a class method on NSObject:
#interface NSObject (Cast)
+ (instancetype)cast:(id)from;
#end
#implementation NSObject (Cast)
+ (instancetype)cast:(id)from {
if ([from isKindOfClass:self]) {
return from;
}
return nil;
}
#end
This version just isn't as nice to use since you have to say something like
UIButton *button = [UIButton cast:someView];
In both versions the resulting value is nil if the cast fails.
Try this macro:
#define objc_dynamic_cast(obj, cls) \
([obj isKindOfClass:(Class)objc_getClass(#cls)] ? (cls *)obj : NULL)
And also don't forget to
#include <objc/runtime.h>
Use it like:
MyClass *safeObject = objc_dynamic_cast(originalObject, MyClass);
I don't think there is.
I think the space for a bug is quite small here.
But if you insist, a macro will do fine?

how to save a variable and use it from two different classes Objective C

I have one Class called "System" it contains some variables and two arrays and I need to access this from two other classes which should be able to read and write that variables
Im a total Beginner so its pretty possible that i already did some mistakes.
System.h
#interface System : UIViewController{
float length_of_one_hour;
float length_of_first_break;
float length_of_second_break;
float length_of_lunch_break;
float length_of_shortned_hour;
float school_begin;
int school_end[5];
float school_length[5];
}
About_now.m
- (void)read_school_end_monday{
school_end_label.text=[NSString stringWithFormat:#"%i", school_end[0]];
}
Settings.m
- (IBAction)set_school_end_monday{
school_end[0]= [school_end_on_mondays_textfield.text intValue];
}
But i don't know what to write in System.h and About_now.m that the variables are saved in System class and can be accessed from anywhere. And Yes I already tried #public and extern.
BTW I need to have an array for the school_end because I'll calculate it (in use of length of an hour and when school actually starts etc.) with a function which already works but i need to access the variables from the About_now class afterwards.
Hope there is someone who can help me. Thanks
A common way to share data across classes in iOS apps is by following the singleton pattern.
SystemModel.h
#import <Foundation/Foundation.h>
#interface SystemModel : NSObject {
#public
float length_of_one_hour;
float length_of_first_break;
float length_of_second_break;
float length_of_lunch_break;
float length_of_shortned_hour;
float school_begin;
int school_end[5];
float school_length[5];
}
+(SystemModel*)instance;
#end
SystemModel.m
#implementation SystemModel
static SystemModel* _instance= nil;
+(SystemModel*)instance {
#synchronized([SystemModel class]) {
if (!_instance)
[[self alloc] init];
return _instance;
}
return nil;
}
+(id)alloc {
#synchronized([SystemModel class]) {
return (_instance = [super alloc]);
}
return nil;
}
-(id)init {
self = [super init];
if (self != nil) {
// your init code
}
return self;
}
#end
Now you can use your instance like this:
float tmp = [SystemModel instance]->length_of_one_hour;
You could also convert instance variables to properties, and use the dot syntax. It does not matter for floats and arrays, but for id-based objects using properties is preferred.
You need a pointer to an instance of System. So to access the member variable:
System* system = GetSystem();
system->school_end[0] = whatever();
This is exactly the same as accessing a member via a struct pointer.
But saying that, it is good practice to hide access via methods:
- (int)getSchoolEndAtIndex:(int)index
{
return school_end[index];
}
You have many design options for doing that:
create a global System object;
make the System class a Singleton;
define the System class interface so that it offers accessors methods for its "properties" at the class level (vs. object level).
instantiate System as it is now and pass it as a initialization parameter to the other two classes.
Now, in more detail:
(1) declare:
extern System* globalSystemObject;
in System.h; then define:
static System* globalSystemObject = nil;
in System.m. Don't forget to initialize globalSystemObject somewhere in your code:
globalSystemObject = [[System alloc] init];
Doing like that, you can use globalSystemObject from any file which imports System.h.
(2) have a look here for details about implementing a singleton class. Keep in mind that many people suggest against using Singleton (if it is only a way to "hide" a global variable). In this specific case, considering the semantics of a class called System, I would say a Singleton is the best option for you.
(3) your class might look like this:
#interface System : UIViewController{
}
+(float)length_of_one_hour;
+(void)set_length_of_one_hour:(float)length;
+(float)length_of_first_break;
+(void)length_of_first_break:(float)length;
...
#end
You would implement those variable in the .m file by means of static variables like in 1.
(4) this is pretty straightforward. The only thing is that you have to create the System instance and those of the other two classes in the same scope:
System* system = [[System alloc] init];
about_now* anow = [[about_now alloc] initWithSystemInstance:system];
...
The system parameter would be stored inside an ivar (or property) of about_now.
Doing like that you avoid altogether the use of global variables (even those hidden behind the Singleton mask).
You could expose the system instance variables via getters/setters (#property / #synthesize) and pass a reference to other classes instances.
#interface System : UIViewController{
float length_of_one_hour;
//...
#property (nonatomic,assign);
..
#end
OtherClass other = [[OtherClass alloc] initWithSystem:sys];
or with a setter
[other setSystem:sys];

How do you past values between classes in objective-c

How do you past values between classes in objective-c?
I'm going to assume the question involves a class, ClassOne, with an instance variable int integerOne, which you'd like to access from another class, ClassTwo. The best way to handle this is to create a property in ClassOne. In ClassOne.h:
#property (assign) int integerOne;
This declares a property (basically, two methods, - (int)integerOne, and - (void)setIntegerOne:(int)newInteger). Then, in ClassOne.m:
#synthesize integerOne;
This "synthesizes" the two methods for you. This is basically equivalent to:
- (int)integerOne
{
return integerOne;
}
- (void)setIntegerOne:(int)newInteger
{
integerOne = newInteger;
}
At this point, you can now call these methods from ClassTwo. In ClassTwo.m:
#import "ClassOne.h"
//Importing ClassOne.h will tell the compiler about the methods you declared, preventing warnings at compilation
- (void)someMethodRequiringTheInteger
{
//First, we'll create an example ClassOne instance
ClassOne* exampleObject = [[ClassOne alloc] init];
//Now, using our newly written property, we can access integerOne.
NSLog(#"Here's integerOne: %i",[exampleObject integerOne]);
//We can even change it.
[exampleObject setIntegerOne:5];
NSLog(#"Here's our changed value: %i",[exampleObject integerOne]);
}
It sounds like you should walk through a few tutorials to learn these Objective-C concepts. I suggest these.