id type instance variable sending messages to instance methods - objective-c

my first question on stackoverflow so please be gentle. I've tried searching for answers but I really need help with this.
The issue is with learning about delegates from Neal Goldstein's Objective-C for Dummies
He has the following in Transaction.h
#import <Cocoa/Cocoa.h>
#class Budget;
#interface Transaction : NSObject {
Budget *budget;
double amount;
NSString *name;
id delegate;
}
//some init method
#end
#protocol TransactionDelegate
#required
- (void) spend: (Transaction *) aTransaction;
//additional optional method
#end
--
//and then in Transaction.m he has this
#import "Transaction.h"
#import "Budget.h"
#implementation Transaction
#synthesize budget, delegate , amount;
- (void) spend {
if ([delegate respondsToSelector:#selector(spend:)])
[delegate spend:self];
}
- (id) initWithAmount: (double) theAmount forBudget: (Budget*) aBudget {
if (self = [super init]) {
budget = aBudget;
[budget retain];
amount = theAmount;
}
return self;
}
- (void) dealloc {
[budget release];
[super dealloc];
}
#end
I have problem understanding the spend method in the Transaction.m file
Can the id type instance variable call ANY method in the class that contains it?
I understand that respondsToSelector is a NSObject method that tells the compiler if a method has been implemented. But how can delegate which is of id-type call that method? the compiler does not even know what object it is yet...
Please help!
P.S. if anybody has any recommendations on good Objective-C books, I'd highly appreciate it. I wanna get into iPhone development but I figured I need to get a good grasp on the basics of Objective-C first.
Thanks!

Yes, you can send any message to the delegate variable, because its type is id.
You wrote this:
[delegate spend:self];
The compiler turns that into a call to the objc_msgSend function, like this:
objc_msgSend(delegate, #selector(spend:), self);
At runtime, the objc_msgSend function searches the method table of delegate's class (and its superclasses) for a method associated with the selector spend:.
Incidentally, we usually declare the delegate variable like this:
id<TransactionDelegate> delegate;
This informs the compiler that delegate will be an object that conforms to the TransactionDelegate protocol. This declaration will help Xcode give you better autocompletion when you're trying to send a message to delegate. If you declare your delegate setter method or property this way, the compiler will also check at compile time that you're setting it to an object that conforms to the protocol.

Good question. Gets at one of the key differences between Obj-C and other compiled languages.
You may send any message to any Objective-C object you like. The message send will try to be resolved by the library called the runtime library and this happens at runtime. At compile time, if you have an object type other than the generic id some IDEs may flag it as a likely user mistake.
At runtime, the runtime library will look for a matching method and then would look whether the class has a fallback handler that wants it and as a last resort would throw an exception. The user code could very well catch this exception and treat it as a normal situation.

Related

Pros and cons of using "id" as the return type of a custom "init" method, instead of a pointer to that class?

Assume the following Objective-C class:
#interface Appliance : NSObject
{
NSString *productName;
int voltage;
}
#end
What are the pros and cons of implementing init method A instead of B?
A) -(id)initWithName:(NSString *)name;
B) -(Appliance *)initWithName:(NSString *)name;
I see they both work in XCode, i.e. they both will result in a valid Appliance instance. "A" seems to be the standard among books I've read and codebases I've looked at, and I'm wondering why this is.
Point in fact, for quite some time the best practice return type from a class initializer (in Objective-C) is instancetype instead of id.
Oh, reopen. :-)
Indeed, you did not ask for the difference id vs. instancetype. And for -init… the answer to this non-asked Q would be easy: There is no difference, because the compiler converts id to instancetype silently.
You asked for id vs. CustomClass*. And you get a completely different answer from me: With CustomClass* a subclass had to cast the result of the superclass' designated initializer. Let's have an example:
#interface BaseClass : NSObject
- (BaseClass*)initWithWhatever; // Typed to class, designated initializer
#end
#implementation BaseClass
- (BaseClass*)initWithWhatever // Typed to class
{
self = [super init]; // What's the return type of -init (NSObject)?
…
}
#end
#interface Subclass : BaseClass
// First problem: I like it to announce in the interface, that a class overwrites
// a method of the base class. Doing so I would have to change the return type. Ugly.
// If I do not redeclare -initWithWhatever it is inherited from BaseClass, still
// having BaseClass* as the return type. Is that the truth? Really?
// However, I do not overwrite it here, but have a new initializer.
- (Subclass*)initWithSomethingElse;
#end
#implementation Subclass
- (Subclass*)initWithSomethingElse
{
// Second Problem:
// First, I have to execute the superclass' designated initializer
self = [super initWithWhatever];
// Wait a minute!
// self is a reference to Subclass. The return value of -initWithWhatever has the type
// BaseClass*. So I assign a reference of the base class to a reference of the subclass:
// Compiler error, false positive. The code is correct.
// So I would have to cast. Ugly, ugly, ugly.
#end
…
// Third problem:
Subclass *object = [[Subclass alloc] initWithWhatever];
// Typing -initWithWhatever to BaseClass* would lead to a compiler error here again.
// Compiler error, false positive. The code is correct.
To make the long story short: Without a mass of castings it would be impossible to type initializers to the concrete class.

From another class, how do I call a method that's declared in the implementation file but not interface?

In this tutorial here: http://www.raywenderlich.com/62989/introduction-c-ios-developers-part-1
It mentions that for Objective-C:
Even if you only declare a method inside the implementation of a
class, and don’t expose it in the interface, you technically could
still call that method externally.
How is this done?
There are a lot of ways.
For example, as long as a compatible method is declared somewhere, you can call it normally with dynamic typing. Here's a demonstration:
// MyClass.h
#interface MyClass : NSObject
#end
// MyClass.m
#interface MyClass()
- (void)addObject;
#end
#implementation MyClass
- (void)addObject:(id)object {
NSLog(#"Whoa, I got called!");
}
#end
// main.m
#import <Foundation/Foundation.h>
#import "MyClass.h"
int main() {
id something = [[MyClass alloc] init];
[something addObject:#"Look ma, no errors!"];
return 0;
}
Since there is a known method named addObject: that takes an object, and id variables are dynamically typed, this is 100% valid and will call MyClass's addObject: method.
They could even get it with a statically typed variable and a method that isn't known by declaring the method in a category. A few other options:
using performSelector: as #michaels showed in his answer
going straight to objc_msgSend()
getting the method IMP and calling it directly.
You can use the performSelector: method of NSObject, though the compiler will give you a warning if the selector is not publicly declared anywhere
[someObject performSelector:#selector(someMethod)];

How to call a delegate's function without getting the "instance method not found" warning in ios?

In the apps I worked on, I often found such lines of code
[delegate aFunction];
that generated the "instance method "aFunction" not found (return type defaults to id)" warning
Now, I did a bit of research on SO and found out that the warning can be removed by declaring the function for cases when you call it on self ([self aFunction];), but none of the answers said anything about my case, when I use a delegate.
So, long story short, what can I do to correctly call a delegate's method inside another class?
Things appear to work fine, so this is not a major issue, but a warning means I'm not doing something completely correct so I would like to learn what's the best practice for such cases
Thank you for your help in advance!
So, if I'm understanding you correctly, your issues can be taken away by declaring your protocol as follows:
#class SomeClass;
#protocol SomeClassDelegate <NSObject>
#required
- (void)thisObjectDidSomething:(SomeClass*)instance;
#optional
- (void)thisObjectDidSomethingUnimportant:(SomeClass*)instance;
#end
Then your delegate ivar and property look like this (use assign instead of weak if you're not using ARC):
#interface SomeClass () {
__weak id<SomeClassDelegate> delegate_;
}
#property (weak) id<SomeClassDelegate> delegate;
And in the .h file of any class that's going to implement that protocol, do this:
#interface TCReader : NSObject <SomeClassDelegate> {
}
Since it's safe to call selectors on nil, for required methods, you can just:
[self.delegate thisObjectDidSomething:self]
But for optional methods, you'd better:
if ([self.delegate respondsToSelector:#selector(thisObjectDidSomethingUnimportant:)]) {
[self.delegate thisObjectDidSomethingUnimportant:self]
}
The main point here is that by declaring and making use of a protocol, you let XCode know that those methods are defined for objects implementing the protocol. If you require that your delegate implement that protocol, then Xcode knows that your delegate has those methods defined.

when to use respondsToSelector in objective-c

- (void)someMethod
{
if ( [delegate respondsToSelector:#selector(operationShouldProceed)] )
{
if ( [delegate operationShouldProceed] )
{
// do something appropriate
}
}
}
The documentation says:
The precaution is necessary only for optional methods in a formal protocol or methods of an informal protocol
What does it mean? If I use a formal protocol I can just use [delegate myMethod]?
You use it pretty much just when you think you need to: to check to see if an object implements the method you are about to call. Usually this is done when you have an optional methods or an informal protocol.
I've only ever used respondsToSelector when I'm writing code that must communicate with a delegate object.
if ([self.delegate respondsToSelector:#selector(engineDidStartRunning:)]) {
[self.delegate engineDidStartRunning:self];
}
You sometimes would want to use respondsToSelector on any method that returns and id or generic NSObject where you aren't sure what the class of the returned object is.
Just to add to what #kubi said, another time I use it is when a method was added to a pre-existing class in a newer version of the frameworks, but I still need to be backwards-compatible. For example:
if ([myObject respondsToSelector:#selector(doAwesomeNewThing)]) {
[myObject doAwesomeNewThing];
} else {
[self doOldWorkaroundHackWithObject:myObject];
}
As kubi mentioned respondsToSelector is normally used when you have a an instance of a method that conforms to a protocol.
// Extend from the NSObject protocol so it is safe to call `respondsToSelector`
#protocol MyProtocol <NSObject>
// #required by default
- (void) requiredMethod;
#optional
- (void)optionalMethod;
#end
Given and instance of this protocol we can safely call any required method.
id <MyProtocol> myObject = ...
[myObject requiredMethod];
However, optional methods may or may not be implemented, so you need to check at runtime.
if ([myObject respondsToSelector:#selector(optionalMethod)])
{
[myObject optionalMethod];
}
Doing this will prevent a crash with an unrecognised selector.
Also, the reason why you should declare protocols as an extension of NSObjects, i.e.
#protocol MyProtocol <NSObject>
Is because the NSObject protocol declares the respondsToSelector: selector. Otherwise XCode would think that it is unsafe to call it.
Old question, but I have learned to be very cautios with using stuff like addTarget:#selector(fu:) because the method name is not checked nor included in refactoring by XCODE. This has caused me quite some trouble already. So now I made it a habbit to always embed stuff like addTarget or addObserver in a respondsToSelector-Check like so:
if([self respondsToSelector:#selector(buttonClicked:)]){
[self.button addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
}else{
DebugLog(#"Warning - a class or delegate did not respond to selector in class %#", self);
}
I know its not super elegant, but i'd rather add some boilerplate code than have an unexpected crash of my apps in the App Store.

Is it possible to make the -init method private in Objective-C?

I need to hide (make private) the -init method of my class in Objective-C.
How can I do that?
NS_UNAVAILABLE
- (instancetype)init NS_UNAVAILABLE;
This is a the short version of the unavailable attribute. It first appeared in macOS 10.7 and iOS 5. It is defined in NSObjCRuntime.h as #define NS_UNAVAILABLE UNAVAILABLE_ATTRIBUTE.
There is a version that disables the method only for Swift clients, not for ObjC code:
- (instancetype)init NS_SWIFT_UNAVAILABLE;
unavailable
Add the unavailable attribute to the header to generate a compiler error on any call to init.
-(instancetype) init __attribute__((unavailable("init not available")));
If you don't have a reason, just type __attribute__((unavailable)), or even __unavailable:
-(instancetype) __unavailable init;
doesNotRecognizeSelector:
Use doesNotRecognizeSelector: to raise a NSInvalidArgumentException. “The runtime system invokes this method whenever an object receives an aSelector message it can’t respond to or forward.”
- (instancetype) init {
[self release];
[super doesNotRecognizeSelector:_cmd];
return nil;
}
NSAssert
Use NSAssert to throw NSInternalInconsistencyException and show a message:
- (instancetype) init {
[self release];
NSAssert(false,#"unavailable, use initWithBlah: instead");
return nil;
}
raise:format:
Use raise:format: to throw your own exception:
- (instancetype) init {
[self release];
[NSException raise:NSGenericException
format:#"Disabled. Use +[[%# alloc] %#] instead",
NSStringFromClass([self class]),
NSStringFromSelector(#selector(initWithStateDictionary:))];
return nil;
}
[self release] is needed because the object was already allocated. When using ARC the compiler will call it for you. In any case, not something to worry when you are about to intentionally stop execution.
objc_designated_initializer
In case you intend to disable init to force the use of a designated initializer, there is an attribute for that:
-(instancetype)myOwnInit NS_DESIGNATED_INITIALIZER;
This generates a warning unless any other initializer method calls myOwnInit internally. Details will be published in Adopting Modern Objective-C after next Xcode release (I guess).
Apple has started using the following in their header files to disable the init constructor:
- (instancetype)init NS_UNAVAILABLE;
This correctly displays as a compiler error in Xcode. Specifically, this is set in several of their HealthKit header files (HKUnit is one of them).
Objective-C, like Smalltalk, has no concept of "private" versus "public" methods. Any message can be sent to any object at any time.
What you can do is throw an NSInternalInconsistencyException if your -init method is invoked:
- (id)init {
[self release];
#throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:#"-init is not a valid initializer for the class Foo"
userInfo:nil];
return nil;
}
The other alternative — which is probably far better in practice — is to make -init do something sensible for your class if at all possible.
If you're trying to do this because you're trying to "ensure" a singleton object is used, don't bother. Specifically, don't bother with the "override +allocWithZone:, -init, -retain, -release" method of creating singletons. It's virtually always unnecessary and is just adding complication for no real significant advantage.
Instead, just write your code such that your +sharedWhatever method is how you access a singleton, and document that as the way to get the singleton instance in your header. That should be all you need in the vast majority of cases.
You can declare any method to be not available using NS_UNAVAILABLE.
So you can put these lines below your #interface
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
Even better define a macro in your prefix header
#define NO_INIT \
- (instancetype)init NS_UNAVAILABLE; \
+ (instancetype)new NS_UNAVAILABLE;
and
#interface YourClass : NSObject
NO_INIT
// Your properties and messages
#end
That depends on what you mean by "make private". In Objective-C, calling a method on an object might better be described as sending a message to that object. There's nothing in the language that prohibits a client from calling any given method on an object; the best you can do is not declare the method in the header file. If a client nevertheless calls the "private" method with the right signature, it will still execute at runtime.
That said, the most common way to create a private method in Objective-C is to create a Category in the implementation file, and declare all of the "hidden" methods in there. Remember that this won't truly prevent calls to init from running, but the compiler will spit out warnings if anyone tries to do this.
MyClass.m
#interface MyClass (PrivateMethods)
- (NSString*) init;
#end
#implementation MyClass
- (NSString*) init
{
// code...
}
#end
There's a decent thread on MacRumors.com about this topic.
If you are talking about the default -init method then you can't. It's inherited from NSObject and every class will respond to it with no warnings.
You could create a new method, say -initMyClass, and put it in a private category like Matt suggests. Then define the default -init method to either raise an exception if it's called or (better) call your private -initMyClass with some default values.
One of the main reasons people seem to want to hide init is for singleton objects. If that's the case then you don't need to hide -init, just return the singleton object instead (or create it if it doesn't exist yet).
Put this in header file
- (id)init UNAVAILABLE_ATTRIBUTE;
well the problem why you can't make it "private/invisible" is cause the init method gets send to id (as alloc returns an id) not to YourClass
Note that from the point of the compiler (checker) an id could potencialy respond to anything ever typed (it can't check what really goes into the id at runtime), so you could hide init only when nothing nowhere would (publicly = in header) use a method init, than the compile would know, that there is no way for id to respond to init, since there is no init anywhere (in your source, all libs etc...)
so you cannot forbid the user to pass init and get smashed by the compiler... but what you can do, is to prevent the user from getting a real instance by calling a init
simply by implementing init, which returns nil and have an (private / invisible) initializer which name somebody else won't get (like initOnce, initWithSpecial ...)
static SomeClass * SInstance = nil;
- (id)init
{
// possibly throw smth. here
return nil;
}
- (id)initOnce
{
self = [super init];
if (self) {
return self;
}
return nil;
}
+ (SomeClass *) shared
{
if (nil == SInstance) {
SInstance = [[SomeClass alloc] initOnce];
}
return SInstance;
}
Note : that somebody could do this
SomeClass * c = [[SomeClass alloc] initOnce];
and it would in fact return a new instance, but if the initOnce would nowhere in our project be publicly (in header) declared, it would generate a warning (id might not respond ...) and anyway the person using this, would need to know exactly that the real initializer is the initOnce
we could prevent this even further, but there is no need
I have to mention that placing assertions and raising exceptions to hide methods in the subclass has a nasty trap for the well-intended.
I would recommend using __unavailable as Jano explained for his first example.
Methods can be overridden in subclasses. This means that if a method in the superclass uses a method that just raises an exception in the subclass, it probably won't work as intended. In other words, you've just broken what used to work. This is true with initialization methods as well. Here is an example of such rather common implementation:
- (SuperClass *)initWithParameters:(Type1 *)arg1 optional:(Type2 *)arg2
{
...bla bla...
return self;
}
- (SuperClass *)initWithLessParameters:(Type1 *)arg1
{
self = [self initWithParameters:arg1 optional:DEFAULT_ARG2];
return self;
}
Imagine what happens to -initWithLessParameters, if I do this in the subclass:
- (SubClass *)initWithParameters:(Type1 *)arg1 optional:(Type2 *)arg2
{
[self release];
[super doesNotRecognizeSelector:_cmd];
return nil;
}
This implies that you should tend to use private (hidden) methods, especially in initialization methods, unless you plan to have the methods overridden. But, this is another topic, since you don't always have full control in the implementation of the superclass. (This makes me question the use of __attribute((objc_designated_initializer)) as bad practice, although I haven't used it in depth.)
It also implies that you can use assertions and exceptions in methods that must be overridden in subclasses. (The "abstract" methods as in Creating an abstract class in Objective-C )
And, don't forget about the +new class method.