How to use Class object in Objective C code - iphone

I have four screens that are exactly the same except they use four different classes. I thought I could reduce them to one by putting this property in my header:
#property Class *classType;
Then I could set the class and be done.
HOWEVER, when I try to use classType like the following:
NSArray *myArray = [classType allobjects];
I get the following: "Bad receiver type __unsafe_unretained Class *"
This really doesn't make much sense. The class method returns and NSArray. When I use the explicit class name there is no error and everything works fine.
I'm using xcode 4.5 with ARC.

Try using
#property Class classType;
Note the missing *. Class is like id, the pointer type is implied.

Quick search on Google, even better in the runtime's headers:
typedef struct objc_class *Class;
The Class type is a pointer itself - you don't need an extra * sign when declaring the property.

Related

getting #encode result from instance instead of the type in objective-c

If you have a type:
#interface Foo: NSObject
#property (nonatomic, strong) NSString *s;
#property (nonatomic) int i;
#end
...
Foo *instance = [[Foo alloc] init];
So, of course, you can get the type encoding:
#encode(Foo); // {<class>=#<encoded ivars>}
But, what if you have the instance? Like:
#encode(instance); // Obviously, not a valid call.
It doesn't seem all that hard to do it with the runtime: You can get the class from the instance, and name and the ivars from the class, and you can get the type encoding from the ivars. So, isn't there some way to do this? What am I missing?
#encode() is a compile-time directive. #encode(instance) is invalid because #encode() operates on types. You could do #encode(typeof(instance)) but that would return "#" because instance is an object pointer type. You could also do #encode(typeof(*instance)) which will give you the encoding of the class that instance is declared to point to (which may differ from the class of object that it actually points to at runtime).
This distinction between declared and actual type is, of course, crucial. There's no way a compile-time directive can anticipate what the actual type will be at runtime.
It's also not clear, for any given use of #encode(), which type you would actually be interested in. If you want the runtime type, use the runtime functions to construct it yourself, as you suggest. If you want the static type, well, you have the type name right there in your code, so just put that into the #encode() directive. (You could use the typeof operator as I showed before, but that just introduces a layer of indirection that's not really helpful. You'll get the same type as is used in the declaration of instance.)
I should say, there are very few good reasons to use #encode(). You're probably a lot better of rethinking your use of it, anyway.

Change the method names of a subclass

I have a subclass of NSMutableArray which in fact deals with a certain type of data i.e. say Employee. The problem is I don't like the inherented names of addObject insertObject and etc. and want to change them to something like addEmployee insertEmployee.
How should I deal with this?
If you are not going to inherit the methods of the superclass then you should not use that superclass!
When you inherit it is a 'is a' relationship between the sub and super classes. "Employer is a NSMutableArray" - no, that is not true and thus don't make Employer a subclass of NSMutableArray. Additionally, in the future you might use a dictionary to store employees (like mapping 'name' -> 'employee') and then having the representation being inherited as an array simply won't work.
#interface Employer : NSObject {
NSMutableArray *employees;
}
- (void) addEmployee: (Employee *) employee;
#end
Like such. Now addObject: isn't workable on instances of Employee; only addEmployee: works. Additionally, you'll only want to specialize methods like filteredArrayWithPredicate: eventually - so it won't be an advantage to inherit them.
You add a method addEmployee: and in that call addObject:. Similar for insertObject:
You can inherit NSMutableArray and add methods like -addEmployee: then add this in your .h file:
- (void)addObject:(id)anObject __attribute__((unavailable("Use -addEmployee:")));
This is a clang extension which will cause a complier error.
References:
How do I flag a function as being deprecated in an iPhone Objective C header file?
http://clang.llvm.org/docs/LanguageExtensions.html#messages-on-deprecated-and-unavailable-attributes

strange behaviour of objective C

Actually I am from java background and I am learning objective c.I am very confused about strange behaviour of objective C."Please Read 3rd Question its important one."
Questions are provided in sequence so please give answers in sequence as its understandable to me and others.
Question 1
I have two classes derived from NSObject: A and B:
#interface A : NSObject
#end
#interface B : NSobject
-(void)display; // It displays "I am class B"
#end
Now if I do this:
A *a = [[B alloc]init]; // Show warning not error (it must be illegal)
[a display]; // prints "I am class B"
It calls the display method of class B. I don't think that it should happen because:
A doesn't have the method display. By polymorphism.
This could be a security threat as I am creating reference of any class and passing object of any another class and accessing data by it.
There could be design issues as Dog class instance gets an object of Printer class and now i am calling print method on Dog instance.
I have reference of NSArray and passed object of NSMutableArray and now i am calling NSMutableArray method on this instance.
[nsarr addObject:#:abc]; //Looking very odd
Question 2
If I have Foo protocol and if any class is not confirming it. It should not be allowed to get object of that class in protocol reference.
#protocol Foo
#required
-(void)abc;
#end
If i call:
id<Foo> obj= [[B alloc]init]; // Shows warning ignore it for now as it must be illegal also
[obj display]; // It will call display method which should be illegal
It should not happen, as B is not conforming to protocol Foo and obj is taking B object and calling B instance method. I think its very bad because of polymorphism and security
Question 3
If my class has a class method which returns an object of that class which is not autoreleased, the compiler shows warning. If I pass the object returned by that class (not conforming protocol) method to reference of protocol. (IT SHOULD BE AN ERROR).
id<Foo> obj = [Abc aClassMethodReturnsObjectWhichNotAutoreleased]; //show warning
It shows a warning which is good. Abc did not conform to the protocol Foo
BUT
id<Foo> obj = [NSArray arrayWithObjects:#"abc",#"def",nil]; // It does **not** show a warning as it will return autorelease object. NSArray doesn't conform protocol Foo
Why does the above assignment to the NSArray class not show a warning as it is showing in the previous example.
Thanks in advance.
EDIT
*Answer 3rd Question:*As NSArray returns id object which will allow to pass in "id obj" but in "aClassMethodReturnsObjectWhichNotAutoreleased" case the method returns "ABC *" pointer so that is why compiler giving warning in this case.
Question 1:
A *a = [[B alloc]init]; //Show warning not error (it must be illegal)
[a display]; //prints "I am class B"
Here you are using a static type A for the variable named a. You are then assigning a different type of object (B) to the variable.
Unlike java, Objective-C does not enforce the static typing requirement, however it does warn you when it is being compiled since the compiler detected a difference between the declared type and the actual type of the object. It happily stuffs the B object into your variable though, so a is now pointing to the B object that you created. Once the program is compiled and running (at run-time), A *a is treated the same as id a.
Another feature of Objective-C is that you can send any message to any object at any time. This is part of the dynamic nature of Objective-C. Obviously there are cases where sending the wrong message to an object can cause bad things (tm) to happen so you need to ensure that you only send appropriate messages. There are various functions that can test the class of an object at run-time, or even test to see if it is able to handle a particular message before you send it in order to prevent the bad things. If you are using static typing (like in this example) then the compiler will issue warnings to tell you that you may have made a mistake and should review the code.
Question 2:
This is actually very similar to question 1. The compiler is warning you that you are assigning what appears to be an incorrect value to the variable, however at run-time you can send any message to any object, so it will work on the actual object instead of the "expected" object from the type declaration.
Question 3:
Good question. I would have thought that you would get a warning there too. Maybe someone else can help out on that. My first thought is that this is a bug and should be reported as such, but there may be a reason for it that I'm not aware of....
Objective-C and Java have very different type rules, as you have discovered.
Java is strictly statically typed, which means that types must match, and you can never make an assignment that is not allowed by the type conversion rules.
Objective-C is dynamically typed with optional static types. You can break out of the type system at any time. For some cases, the compiler will emit warnings, but it is still allowed.
This is the reason why you are seeing the behavior. Objective-C is not broken, it just have different rules than the ones you know from Java.
Apple has a lot of documentation of the specific rules, perhaps you would want to read Enabling Static Behavior.
Here are some more resources about dynamic vs static typing for you:
Dynamic type languages versus static type languages and What do people find so appealing about dynamic languages?
A *a = [[B alloc]init]; //Show warning not error (it must be illegal)
[a display]; //prints "I am class B"
Because you initialized variable from B class that have display property.
It's correct

How to set up non-instantiated classes in Objective-C (Classes with just methods)

I'm looking to create a class in Objective-C for an iOS project that is focused on fetching data. I'm familiar with how classes normally work, setter and getter methods and variables. However, for this class since it's only performing a function (returning NSMutableArrays) I don't want to have to create an instance of the class to use the methods inside the class.
Any idea how I can do this neatly and efficiently?
This is a little bit atypical in Objective-C. Since classes in Objective-C can't actually have state beyond what is available to ordinary functions (i.e. there are no class variables), a class that's never instantiated is relatively useless in most cases. The normal design patterns for this kind of functionality are:
A singleton class (if you need lots of state)
A set of functions (if you don't)
You want to make class methods?
#interface Foo : NSObject {}
+(NSMutableArray*)someClassMethod:(id)params;
#end
...
#implementation Foo
+(NSMutableArray*)someClassMethod:(id)params {
// whatever implementation
return nil;
}
#end
...
NSMutableArray* array = [Foo someClassMethod:nil];
If you're only performing functions, and you don't need to support subclassing etc, why not just write them as C functions rather than a class with methods?
If this is just a class that performs some functions, you could write it as a C function.
In your header file --
NSMutableArray *functionThatReturnsMutableArray(NSObject *param1, NSString *param2);
In your implementation file --
NSMutableArray *functionThatReturnsMutableArray(NSObject *param1, NSString *param2)
{
...
return aMutableArray;
}
And that just include the .h file in your class that needs these functions and call them directly.
NSMutableArray *anArray = functionThatReturnsMutableArray(param1, param2);
Depending on what you are doing (the same NSString operations, UIView manipulations, etc), you could implement a category (I answered a question yesterday with the explanation below -- copied for your convenience ;).
Categories extend an existing class with additional methods or with your version of existing methods. For example, let's say you want to add a method that returns the first letter of a string to NSString. To do this you would create a category as follows:
Interface - JULString.h
#import NSString
#interface NSString (JULString)
-(NSString *) firstLetter;
#end
Implementation - The typical convention is that the filename of the category is the name of the class you are extending followed by “+” and the name of the category. In this case the file would be called NSString+JULString.m
#import "NSString+JULString.h"
#implementation NSString ( JULString )
- (NSString *)firstLetter
{
return [NSString stringWithFormat:#"%C", [self characterAtIndex:1]];
}
#end
The neat thing about categories is that now they extend the behavior of ANY instance of the class you are working with. In other words, any NSString in your application will have your new methods (provided that you import the proper header file of course). Beware though, as with great power comes great responsibility. Overwriting class using a category behaviors may lead to undesired effects, so be cautious.
A couple of links you may want to check are:
Apple's guide to Objective-C
Learn Objective-C
Note:
I don't have my Mac with me so I'm writing this code basically off the top of my head (and using some code from the sites above as a reminder). So I apologize in advance for any mistakes ;)

How to typecast an id to a concrete class dynamically at runtime?

I have several dataSources I use for one UIViewController. My view controller uses KeyValue Observing in order to follow the state of certain properties at runtime. When I swap dataSources, I need to stop observing those properties. The problem is, I'm not sure of the class of the dataSource at runtime, therefor something like this is not valid:
if (aDataSource != dataSource) {
// Ensure we stop observing the existing dataSource, otherwise bad stuff can happen.
[dataSource removeObserver:self forKeyPath:#"someKeyPath"]; // not valid, compiler doesn't know what class dataSource is.
[dataSource release];
dataSource = [aDataSource retain];
}
The compiler needs a concrete class in order to know the object's interface. How can I grab the class of dataSource in this particular case, and then typcast the dataSource for the removeObserver:forKeyPath: selector above? I prefer something dynamic/smarter than caching the name of the class in an NSString instance and referring to that whenever I switch. Meaning, I could always do something like:
NSString *lastDataSource = #"MyClass";
Class foo = [NSClassFromString(lastDataSource)];
Thanks.
If you code like this:
id foo = ...;
[foo removeObserver:self forKeyPath:#"someKeyPath"];
The compiler will be fine with it as objects with type id accepts any message (as long the signature is known to the compiler).
Now if you have:
id<NSObject> foo = ...;
[foo removeObserver:self forKeyPath:#"someKeyPath"];
The compiler will give you a warning:
warning: '-removeObserver:forKeyPath:' not found in protocol
This is because you're referring to the protocol NSObject not to the NSObject class where the KVO methods are defined.
But if you have:
NSObject* foo = ...;
[foo removeObserver:self forKeyPath:#"someKeyPath"];
That will compile fine too, as in this case you're using the class NSObject.
Related links:
Objective-C protocol
The id Type and Protocols
What do you mean it is not valid? Do you get a compile error?
Objective-C supports dynamic typing for objects by default. You should be able to call any method on any object in Objective-C, even if the compiler can't guarantee from the static type that that object supports that method.
I think you need to cast them to NSObject *, since that's where the KVO methods are (not in NSObject protocol).
Just let me add that the approach you outline with ...
NSString *lastDataSource = #"MyClass";
Class foo = [NSClassFromString(lastDataSource)];
... will of course not be able to supress your compile-time warnings, since the class "foo" will only get calculated at run-time. So even though you as the programmer can plainly see from the code that "foo" will end up being the class "MyClass", this is not clear to the compiler, and so if "MyClass" has a method "myMethod:" you will still get a compiler warning if you send that message to an object declared as "foo".
I'm guessing you realise this, but it's better to make it clear why that approach won't solve your problem.