declare and access a BOOL class method - objective-c

Mehul has defined this method.
+(BOOL)isCameraDeviceAvailable
{
BOOL isCameraAvailable=NO;
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
if([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront] || [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear])
isCameraAvailable = YES;
}
return isCameraAvailable;
}
But I cannot declare it properly and am getting the error
Instance method '-isCameraDeviceAvailable' not found (return type defaults to 'id')
when I declare it as follows.
+ (BOOL)isCameraDeviceAvailable;
and then use it this way
if([self isCameraDeviceAvailable]){
}
I suppose I need to declare it in a different place or in a different way. Can you tell me how to do this?

[self isCameraDeviceAvailable]
is an instance method call, not a class method call.
You have to use it like this:
[MyClass isCameraDeviceAvailable]

+(BOOL)isCameraDeviceAvailable
The + at the beginning of the line makes this a class method, which means that you can only send isCameraDeviceAvailable to the class. If you want to use the method with an instance of that class, you'll need to declare it that way by using a - instead of +:
-(BOOL)isCameraDeviceAvailable
Or, as Kashiv explains, you can use the method as you have it by sending isCameraDeviceAvailable to the class instead. See Objective-C Classes Are also Objects for more information.

Related

Why doesn't this method let me reference anything?

I recently created a method that can be called from other classes, this is my code.
In the ViewController1.h
+ (void)updateName:(id)sender;
In the ViewController1.m
+ (void)updateName:(id)sender {
}
The method is calling and working which is good however I have another method in the ViewController1.m file which is
-(void)updateString {
NSLog(#"IT WORKED");
}
However, I try to call it in my updateName method like this:
+ (void)updateName:(id)sender {
[self updateString];
}
But I get an error saying "no known class method for selector 'updateString' " Can anyone tell why is this happening and how I can call this method? Thanks.
The + in front of the method denotes a class method i.e. you don't need to create a new instance of ViewController1 in order to call the method. Where as [self updateString] is an instance method i.e. you need to create a new instance of the class in order to perform it. The problem here is the difference in scope. See below:
Inside another class:
[ViewController1 updateName:SOMETHING];
vs
ViewController1 *newViewController1 = [[ViewController1 alloc] init];
[newViewController1 updateString];
EDIT
If you want to call that method from that class you can do this?
+ (void)updateName:(id)sender {
[ViewController1 updateString];
}
But that won't be able to reference or update any class properties etc.. So from the names of your methods, this is likely not going to solve your problem.
Does that make sense ?
You're doing something odd but to fix your problem simply replace the - with + in front of your method name.

What should be done with inherited factory methods?

Suppose I have a class BasicDate, and a subclass of BasicDate called EuroDate. The difference between the classes is month-day-year versus day-month-year. I know it'd probably be better to just have methods on the same class to output them differently... but that's not the point of this question.
BasicDate has the following init method:
-(id)initWithMonth:(int)m andDay:(int)d andYear:(int)y {
if(self = [super init]) { /*initialize*/ } return self;
}
And the matching factory method then looks like this:
+(BasicDate)dateWithMonth:(int)m andDay:(int)d andYear:(int)y {
return [[BasicDate alloc] initWithMonth: m andDay: d andYear: y];
}
But if my subclass, EuroDate which would use a factory method more like this:
+(EuroDate)dateWithDay:(int)d andMonth:(int)m andYear:(int)y {
return [[EuroDate alloc] initWithDay: d andMonth: m andYear: y];
} //we can assume that EuroDate includes this init method...
This is all fine. Now, we assume that both classes have their own description method, which will print MMDDYYYY for BasicDate, but DDMMYYYY with EuroDate. This is still all fine.
But if I do this:
EuroDate today = [EuroDate dateWithMonth:10 andDay:18 andYear:2013];
This will call the BasicDate factory method that EuroDate has inherited. The problem is, remember how BasicDate's factory method looks? return [[BasicDate alloc] ...]
So today polymorphs into a BasicDate despite me wanting to store it as a EuroDate, so if I call the description method, it will print 10182013 rather than 18102013.
There are two solutions to this problem I have found.
Solution 1: Change BasicDate's factory method. Rather than return [[BasicDate alloc] ..., I can instead do return [[[self class] alloc] ...] This works and will allow me to use this method for BasicDate or any of BasicDate's subclasses and it will return the right object type.
Solution 2: Override the factory method. Whether I override it to throw an exception or override it to do return [[EuroDate alloc] ...]. The problem with overriding it is that I have to override every factory method for every subclass.
Which is better? What are some downsides to the two possible solutions that I may be missing? What is considered the standard way of handling this issue in Objective C?
You should generally use [[[self class] alloc] init...] in factory methods to ensure that they create instances of the correct class. Note that class isn't a property (and in fact, there's no such thing as a 'class property') so the use of dot syntax there is inappropriate.
Edit
And as pointed out by #ArkadiuszHolko (and Rob, thanks), you should now use instancetype rather than id for the return value, to get the benefits of strong typing while maintaining type flexibility for subclasses. And by the way, Apple's naming conventions suggest avoiding using the word 'and' in method names. So consider rewriting your convenience method like so:
+ (instancetype)dateWithMonth:(int)month day:(int)day year:(int)year
{
return [[self alloc] initWithMonth:month day:day year:year];
}

The best way to know an instance type from a class method of the same class?

I want to learn how to make class methods to return instancetype values instead of id.
Simple demonstration:
#implementation MyGenericManagedObject
+ (instancetype)existingObjectByObjectID:(NSManagedObjectID *)objectID {
return (__typeof([self alloc]))[managedObjectContext() existingObjectWithID:objectID error:nil];
}
Having this method written this way, it does work, but if I remove (__typeof([self alloc])) I begin getting "Incompatible pointer types casting 'NSManagedObject *' to type 'MyGenericManagedObject *'.
What is the right way to get instance type from inside a class method of the same class?
existingObjectWithID:error: is explicitly typecast to return NSManagedObject*. That, frankly, is a bug in the API and you should file it.
Because of that, you'll need the cast.
#implementation MyGenericManagedObject
+ (instancetype)existingObjectByObjectID:(NSManagedObjectID *)objectID {
return (id)[managedObjectContext() existingObjectWithID:objectID error:nil];
}
Just casting to id should work.

Objective-C calling a method from another method

Say if i have a method as follows;
- (void)carpentorLoad {
NSlog(#"HI... Hello");
}
Now, i need to call this method from another method, say - (int) CallingMethod
-(int) CallingMethod{
// Here, i need to call carpentorLoad Method
return 0;
}
How should i call carpentorLoad from CallingMethod do this?
Are these methods in the same class? If so you can just do:
- (int) CallingMethod {
[self carpentorLoad];
return 0;
}
If they are in different classes, then you'll need to pass a reference to the second class into your calling method, like:
- (int) CallingMethod: (Carpentor*)theCarpentor {
[theCarpentor carpentorLoad];
return 0;
}
Assuming they are the same object, you would call [self carpentorLoad].
If carpentorLoad is a member of another class, either call [<ClassName> carpentorLoad] or [<yourObject> carpentorLoad], depending on if it is a static or instance method, respectively.
In Objective-C, you don't call methods, you send messages. The Obj-C runtime matches your message to a method in the reciever's class or one of its ancestor classes, and then calls the method it finds.

Objective-C subclass and base class casting

I'm going to create a base class that implements very similar functions for all of the subclasses. This was answered in a different question. But what I need to know now is if/how I can cast various functions (in the base class) to return the subclass object. This is both for a given function but also a function call in it.
(I'm working with CoreData by the way)
As a function within the base class (this is from a class that is going to become my subclass)
+(Structure *)fetchStructureByID:(NSNumber *)structureID inContext:(NSManagedObjectContext *)managedObjectContext {...}
And as a function call within a given function:
Structure *newStructure = [Structure fetchStructureByID:[currentDictionary objectForKey:#"myId"]];
inContext:managedObjectContext];
Structure is one of my subclasses, so I need to rewrite both of these so that they are "generic" and can be applied to other subclasses (whoever is calling the function).
How do I do that?
Update: I just realized that in the second part there are actually two issues. You can't change [Structure fetch...] to [self fetch...] because it is a class method, not an instance method. How do I get around that too?
If I understand your question correctly I believe the key is the [self class] idiom.
As far as your update goes requesting a way to call a class method on the current class you can use [self class]. As in:
Structure *newStructure = [[self class] fetchStructureByID:[currentDictionary
objectForKey:#"myId"]];
inContext:managedObjectContext];
EDIT: I redid this to return id per #rpetrich's comment -- much cleaner and avoids the need for -isKindOfClass: as long as you're sure of the type of the instance you're calling -createConfiguredObject on.
As for the first part, you could just return an id (pointer to any object) and document that it will return an instance of the same class it's called upon. Then in the code you need to use [self class] anywhere you instantiate a new object in a method.
e.g. if you have a -createConfiguredObject method which returns an instance of the same class it's called on, it would be implemented as follows:
// Returns an instance of the same class as the instance it was called on.
// This is true even if the method was declared in a base class.
-(id) createConfiguredObject {
Structure *newObject = [[[self class] alloc] init];
// When this method is called on a subclass newObject is actually
// an instance of that subclass
// Configure newObject
return newObject;
}
You can then use this in code as follows:
StructureSubclass *subclass = [[[StructureSubclass alloc] init] autorelease];
subclass.name = #"subclass";
// No need to cast or use isKindOfClass: here because returned object is of type id
// and documented to return instance of the same type.
StructureSubclass *configuredSubclass = [[subclass createConfiguredObject] autorelease];
configuredSubclass.name = #"configuredSubclass";
For reference, what I was referring to with -isKindOfClass: and casting to the proper subclass is as follows:
Structure *structure;
// Do stuff
// I believe structure is now pointing to an object of type StructureSubclass
// and I want to call a method only present on StructureSubclass.
if ([structure isKindOfClass:[StrucutreSubclass class]]) {
// It is indeed of type StructureSubclass (or a subclass of same)
// so cast the pointer to StructureSubclass *
StructureSubclass *subclass = (StructureSubclass *)structure;
// the name property is only available on StructureSubclass.
subclass.name = #"myname";
} else {
NSLog(#"structure was not an instance of StructureSubclass when it was expected it would be.");
// Handle error
}