From reference: Can someone explain what a delegate is with an example?
NICK wrote:
For example, class A asks you for a
delegate. You tell it [this] instance
of class B will do.
[a setDelegate:b];
What is a? Is it a instance of Class of A?
Sending messages to objects using Objective-C is done using the square brackets.
You have instance methods, they are denoted with a - (minus) sign ahead of the return type of the method, like so:
- (void)setDelegate:(id <SomeDelegateProtocol>)delegate;
Alternatively you have the class methods denoted with a + (plus) sign:
+ (NSArray *)arrayWithObject:(id)object;
The first text within the brackets stands for the receiver of that message, in case of an instance message this will be an object pointer. Otherwise, when you deal with a class message, you use the class it's name.
So a is indeed a pointer for an instance, probably of class A (well, it actually is just the name of the variable the object is assigned to. It can be of any class).
This example is presuming that we have two classes, class A and class B, and that we have one instance of each of them; a is an instance of A, and b is an instance of B:
ClassA *a = [[[ClassA alloc] init] autorelease];
ClassB *b = [[[ClassB alloc] init] autorelease];
We're also presuming that class A has some kind of delegate variable, and a method setDelegate: that changes the value of that variable. In general, a delegate is an instance of an object that receives messages about another object's activities or defines its behavior in some way. So, for example, if class A has some method doFoo, class B might have a delegate method a:didFoo: that gets called from class A whenever it does Foo.
But before the delegate can fulfill its purpose, the object it's to receive messages about has to know that it has a delegate. So we have to set our instance of class B as class A's delegate by using class A's setDelegate: method:
[a setDelegate:b];
The short answer is:
Yes.
Hope that clears things up.
For longer answers see Tim & JoostK.
If you're not familiar with Obj-C's message passing syntax you should probably get more practice with that before worrying about delegates. Once you understand message passing, delegates are straightforward.
Related
Let's say I have an Objective-C class that's intended to be a singleton — its init method checks if there's already an instance of that class and returns it.
Now suppose you have two subclasses of this class, A and B, and that you do:
[[A alloc] init];
[[B alloc] init];
Now, when B's init calls super init, the latter returns an A. What happens when B's init tries to set ivars of B, which don't exist because self is actually an A? Will it corrupt memory, assign an int to an object pointer, etc?
What happens when a message is sent to the object that's defined only in B? I'm assuming you will get a runtime error saying that the selector doesn't exist. Correct?
This question already has answers here:
Create a subclass of a class using parent's init - from another class
(2 answers)
Closed 8 years ago.
EDIT: Yes, I did it wrong. It's well possibly knowing the init method by using a protocol on class level. This is something I rarely do, so that didn't come to my mind at first (see linked question about my answer to it using a protocol). So yes, this question is broken. As bbum said, there should be absolutely no reason to do this.
Background to my question in [1].
For a design reason (data mapper pattern) I need to initialize classes which I know are subclasses of a certain base class (ManagedEntity). I assert for this once - then later I want to create as many instances, and as fast as possible (I'm programming for iOS). However, since the class where I need to create the concrete instances in doesn't know any of the model classes, the meta class stored and used to create entity instances of is just known to be of type Class.
Long story short: I can't simply use [[[_EntityClass] alloc] initWithBlah:something], since EntityClass is unknown, just known as type Class there, hence the init method initWithBlah is unknown of course - but I know it must exist (it must be by design a subclass of the base class, which is asserted once when the mapper is initialized).
So in order to create instances of the unknown class with the init method that I know it exists, I need to construct a method invocation. This should call the initWith:something selector on the unknown class and create an instance of it.
I think I should use objc_msgSend rather than NSInvocation, because the latter is supposed to be an order of magnitude slower [2]. The init method is supposed to not change, and requires one argument.
So... What would be the equivalent to:
ManagedEntity *newEntity = [[ManagedEntity] alloc] initWithEntityDescription:_entityDescription];
with objc_msgSend?
[1] Create a subclass of a class using parent's init - from another class
[2] http://www.mikeash.com/pyblog/performance-comparisons-of-common-operations-leopard-edition.html
Better:
Class klass = NSClassFromString(className);
id newEntity = [[klass alloc] initWithEntity:entity insertIntoManagedObjectContext:ctx];
There is no reason to use objc_msgSend() directly when you have a fixed selector. You can always call the selector directly using the normal syntax. Worst case, you might have to type-cast the return value of one of the calls.
The only requirement is that the compiler has seen the declaration of initWithEntity:insertIntoManagedObjectContext: sometime prior to compiling the above call site.
Example:
#interface NSObject(BobsYourUncle)
- (void)bob:sender;
#end
...
Class klass = NSClassFromString(#"NSManagedObject");
[[klass alloc] bob:nil];
The above compiles just fine. Not that I'd recommend hanging random definitions off of NSObject. Instead, #import the abstract superclass's declaration (which should contain the selector declaration).
id cls = NSClassFromString(className);
id alloced_cls = objc_msgSend(cls, #selector(alloc));
id newEntity = objc_msgSend(alloced_cls, #selector(initWithEntity:insertIntoManagedObjectContext:), entity, ctx);
return newEntity;
I'm reading an Objective-C book and I have a question that the book doesn't seem to really answer.
Let's say I have two custom-made classes.
The first class is called ClassA. It has both the .h and .m files of course. The second class is called ClassB. It also has both .h and .m files.
Somewhere in the code, 'ClassA' has this method:
-(IBAction)displaySomeText:(id)sender {
ClassB *myNumber = [[ClassB alloc]init];
NSString *numberString = [myNumber storedNumberAsString];
// storedNumberAsString is just a method that returns a string object that holds
// myVariable.
[textView insertText:numberString];
//textView is a object I created that just displays some text on screen.
[myNumber release];
}
The book tells me that ClassB should have a method:
-(id)init {
[super init]; //I know why this is done, the book explains it well.
myVariable = 42; // I created this variable already in the ClassB .h file
return self;
}
Now, when in the Interface Builder I click the buttons I connected, etc. It works, the number displayed is 42.
My question is, why do I have to create an -(id)init method for ClassB, if I can do the following in ClassA's method:
-(IBAction)displaySomeText:(id)sender {
ClassB *myNumber = [[ClassB alloc]init];
myNumber.myVariable = 42; //I just do this to skip the -(id)init method.
NSString *numberString = [myNumber storedNumberAsString];
[textView insertText:numberString];
[myNumber release];
}
Doing this, it still displays the same value: 42. I can change it to whatever I like. So why not just use the init inherited from NSObject and just do the simple way myNumber.myVariable = 42?
Suppose that the value of the instance variable were something more complicated than an integer. Suppose it involved reading a string from a file, or getting some information over the network, or just doing some arithmetic. In that case, it wouldn't make sense to have ClassA be responsible for setting that value correctly. That would break the encapsulation that makes it useful to have separate classes in the first place.
In this extremely simple case, you're quite right, there may be no reason to have a custom initializer for ClassB, but in general, a class should itself be responsible for its state being set up correctly. Foisting that responsibility off on other classes means that those others need to know about the internals of the first, meaning the two may be too tightly coupled.
In some cases, the value of the ivar might be a piece of information that is known only to ClassA, or needs to be calculated based on such a piece of information. Then you should create a custom initializer for ClassB which receives that value, e.g., - (id) initWithInteger: This would become the "designated initializer", and you would then override -[ClassB init] to call it with some reasonable default value.
If instances of ClassB do not have to have anything initialized (other than to nil/zero), you do not need to create an explicit init method for ClassB. In this case the question is whether setting myVariable to 42 is ClassB's answer to life, the universe, and everything, or whether myVariable is just a field in ClassB that could be set to any value.
That is, the issue is conceptual, not of physical significance. If conceptually the value 42 "belongs" to ClassB, then there should be an init method for ClassB that sets it. If that specific value has more meaning to ClassA than to ClassB then some method of ClassA should set it. If you do it "wrong" the code still works fine, but your design is slightly less elegant, slightly less extendable, slightly less robust.
This is kind of a tricky issue. I was "brought up" to think that after a constructor (initializer) runs, the object should be ready to go. You should be able to safely call any method on it. Therefore, you need to set up any instance variables in the constructor for which 0 is not a valid value. I like to set them up if they have 0 values anyway, just for sanity, because I never want to bother to know the minute details of every language I work with, like whether they initialize instance variables to 0 automatically.
However, there are some arguments for not initializing some variables.
The initialization is complex, like loading a file or getting data from the network. You want to keep open the possibility of creating an instance and waiting until you're ready to do heavy weight operations.
There are quite a lot of instance variables that are configurable. Your options are to make a constructor with umpteen arguments, or make a constructor with no or a few arguments, and let the caller decide which values should be set to non-default values by property setters.
You need to set up a whole object graph before you can meaningfully initialize a value. That is, initializing the value might have side effects that depend on other related objects. The best solution is to construct each object, then use property setters to set the relationships between objects, then use property setters to initialize attribute values.
Why do some objects not need to be initialized before use in objective-c?
For example why is this NSDate *today = [NSDate date]; legal?
They are initialized within the date method. This is a common way to create autoreleased objects in Objective-C. Allocators of that form are called convenience allocators.
To learn more about that, read the "Factory Methods" paragraph in Apple's Cocoa Core Competencies document about Object Creation: http://developer.apple.com/library/mac/#documentation/General/Conceptual/DevPedia-CocoaCore/ObjectCreation.html
To create convenience allocator for you own classes, implement a class method, named after your class (without prefix). e.g.:
#implementation MYThing
...
+ (id)thing
{
return [[[MYThing alloc] init] autorelease];
}
...
#end
today is initialized (and autoreleased) inside the static date call.
You only need to called an init… method on objects you have allocated by calling alloc. alloc only reserves space needed for the object, creating a an unitialized object.
An uninitialized object have all instance variables set to zero, nil, or equivalent for the type. Except for the retain count that is set to 1.
All other methods that return an object are guaranteed to return a fully initialized object. alloc is the exception.
You must never call an init… method on an object that is already initialized. Simple rule on thumb is to use a 1-to-1 relation between alloc-init…, thats it.
Two parts.
First, as others have mentioned, a method can initialise and then autorelease an object before returning it. That's part of what's happening here.
The other part is how it's defined. Note how most Objective C definitions begin with a -? The one you mention does not. The signature looks like this:
+ (NSDate*) date;
That is, it's a class method and applies to the class as a whole rather than to an instance of that class.
In Objective-C, what's the difference between declaring a variable id versus declaring it NSObject *?
With a variable typed id, you can send it any known message and the compiler will not complain. With a variable typed NSObject *, you can only send it messages declared by NSObject (not methods of any subclass) or else it will generate a warning. In general, id is what you want.
Further explanation: All objects are essentially of type id. The point of declaring a static type is to tell the compiler, "Assume that this object is a member of this class." So if you send it a message that the class doesn't declare, the compiler can tell you, "Wait, that object isn't supposed to get that message!" Also, if two classes have methods with the same name but different signatures (that is, argument or return types), it can guess which method you mean by the class you've declared for the variable. If it's declared as id, the compiler will just throw its hands up and tell you, "OK, I don't have enough information here. I'm picking a method signature at random." (This generally won't be helped by declaring NSObject*, though. Usually the conflict is between two more specific classes.)
id means "an object", NSObject * means "an instance of NSObject or one of its subclasses". There are objects in Objective-C which are not NSObjects (the ones you'll meet in Cocoa at the moment are NSProxy, Protocol and Class). If some code expects an object of a particular class, declaring that helps the compiler check that you're using it properly. If you really can take "any object" - for instance you are declaring a delegate and will test all method sends with respondsToSelector: calls - you can use an id.
Another way to declare an object variable is like "id <NSObject>", which means "any object which implements the NSObject protocol.
From my limited understanding of Objective-C, not all objects are derived from NSObject (unlike Java where all objects derive from Object). You can theoretically have other root objects. id could apply to any of those non-NSObject derived objects.
I would like to add another difference. When you add a protocol to id, it does not longer mean that it will be of type NSObject *, it just means that it will be any class that confirms to that protocol.
So, for example, this code will not throw any error, since NSObject's category NSDelayedPerforming has that method:
id testId;
[testId performSelector:#selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5];
However, this code will show the error No known instance method for selector "performSelector:withObject:afterDelay:":
id<NSMutableCopying> testId;
[testId performSelector:#selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5];