2

I've just been reading and learning about instancetype and how in most cases it should be used instead of id in modern objective-c. Can I just ask when, then, would it be advisable to actually use id and not instancetype? Thanks.

cheznead
  • 2,589
  • 7
  • 29
  • 50
  • And good one about this, which is even more appropriate than link above : http://stackoverflow.com/a/14652187/3402095 – Whirlwind May 19 '15 at 12:22
  • Yes, I've just been reading that Whirlwind, but I need the id use cases to round off what I've learned. – cheznead May 19 '15 at 12:39

5 Answers5

8

id

id is the generic type variable. Id doesn't warn us at compile time but it will crash if there is any problem.

Instancetype

instancetype does type checking for us at compile time to warn us of problems.

eg:

Animal.h

@interface Animal : NSObject

+ (id)giveMeAnimalA;
+ (instancetype)giveMeAnimalB;
+ (Animal *)giveMeAnimalC;

@end

Animal.m

@implementation Animal

+ (id)giveMeAnimalA {
    return [[[self class] alloc] init];
}

+ (instancetype)giveMeAnimalB {
    return [[[self class] alloc] init];
}

+ (Animal *)giveMeAnimalC {
    return [[[self class] alloc] init];
}

@end

Suppose if we use [[Animal giveMeAnimalA] count];

The compiler will warn us of nothing, but we will crash at runtime with an exception because Animal doesn't have a count method.

And If we use [[Animal giveMeAnimalB] count];

The compiler would immediately warn us that Animal does not have a count method, and we could avoid crashing at runtime. But wouldn't it be simpler just to make our return type Animal* ?

Imagine we have a Dog subclass of Animal:

@interface Dog : Animal

- (void)makeSound;

@end

Now if we tried to call

[[Dog giveMeAnimalC] makeSound];

This wouldn't work because we would have been returned an Animal that doesn't have a makeSound method.

abhishekkharwar
  • 3,529
  • 2
  • 18
  • 31
3

For complete last answer, i suggest you an example when Id is supported. It's on the ForIn Loop (fast enumeration)

Imagine, you have an array with three different objects like below :

    NSArray *anotherArray = @[@"One element of Another Array",@"Second Element of Another Array"];
    NSArray *array = @[@"First",@[anotherArray],@(12)];

    for (id item in array)
    {
        if ([item isKindOfClass:[NSString class]])
        {
            NSLog(@"Im a NSString");
        }

        if ([item isKindOfClass:[NSArray class]])
        {
            NSLog(@"Im a NSArray");
        }

        if ([item isKindOfClass:[NSNumber class]])
        {
            NSLog(@"Im a NSNumber");
        }


    }
1

The id is a generic data type which can hold any type of data like nsstring,uiimage,nsarray and remaining all,so if you are having the requirements like returning the objects dynamically from a method you better use the return type of that method as id,hope you will get it

Naresh Reddy M
  • 1,096
  • 1
  • 10
  • 27
1

You can not use instancetype as return type when the type of the value that is returned is not known beforehand. If a method might return either an NSButton or an NSString depending on context, you can only use id.

instancetype is just a placeholder for the class that it is being used in; if a method of class Foo is like

- (instancetype) getMeFoo

then it is equivalent to

- (Foo *) getMeFoo

It can not return an NSString; the compiler would complain. However,

- (id) getMeFoo

can return any class type.

You could theoretically use a common superclass of the possibly returned types (for example, NSObject); but then you would need to typecast it when assigning to a concrete variable, or the compiler would bug you with warnings.

- (NSObject *) getMeFoo {
    return @"foo!";
}
NSString *myString = (NSString *)[self getMeFoo];

The id type is "automatically" cast:

- (id) getMeFoo {
    return @"foo!";
}
NSString *myString = [self getMeFoo];

But never forget to check if you really got the expected type:

NSString *myString = [self getMeFoo];
if (![myString isKindOfClass:[NSString class]]) {
    // Danger, Will Robinson!
}
fbitterlich
  • 882
  • 7
  • 24
1

"I've just been reading and learning about instancetype and how in most cases it should be used instead of id in modern objective-c. Can I just ask when, then, would it be advisable to actually use id and not instancetype? Thanks."

You learned wrong. Kind of. The problem is that a language like Objective-C is complicated, and every rule will come with a long list of "do this IF a and b and c"... which you have to understand.

instancetype is used in one very particular situation: As the return type of init methods. You can't use for example UIButton* because an init method of UIButton could be used by a subclass, so the init method doesn't actually a UIButton but some subclass. That's why "id" was used which means "some object but I have no idea which object actually". "instancetype" on the other hand tells the compiler "you are clever, you figure it out. So with [[UIButton alloc] init] the compiler knows it returns UIButton*. [[MyButtonSubclass alloc] init] the compiler knows it returns MyButtonSubclass*.

In no other situation would you use instancetype.

Always give the compiler as much information as you can. If you have an object declared as UIButton* the compiler knows it's a UIButton or a subclass. If you have an object declared as id the compiler knows nothing. That means the compiler can't tell you if you do something stupid (like assigning a UIButton* to an NSString*, or calling the length method on a UIButton).

gnasher729
  • 51,477
  • 5
  • 75
  • 98