NSTmer *t not used in updateLastTime

I am just curious why we have the parameter (NSTimer *)t in the method updateLastTime? We don’t use it explicitly, and the code seemed to work fine when I took it out? Will it be used in a later chapter or something?

Also, while I am here, perhaps there is something similar going on with the protocol methods. They parameter (NSURLConnection *) connection is not explicitly used in these methods. In this case, I suppose these methods require this argument. I am wondering if behind the scenes these parameters get used somehow from the methods used in main.

That’s a really good observation.

There are two patterns at work, one of which feels weird and magical, but it’s not.

  1. The protocol methods - methods often declared by a type using the delegation or data source design patterns - already have pre-defined signatures. When a delegating object wants to send a method that it listed in the protocol, it uses the -respondsToSelector method to ask its target “do you implement this method?” before calling it. But it only asks for that one, specific method signature. If it’s not implemented, it doesn’t get called.

  2. The strange behavior of the target-action design pattern - the pattern used by NSTimer, UIButton, and many others - comes down to how the messages are actually sent. When you configure the timer, you gave it a selector. The timer expects a selector that, in turn, takes an argument of type NSTimer *, as indicated in Apple’s NSTimer documentation.

When the timer gets around to calling your method, it uses code that looks like this:

That is, the timer calls on your object the performSelector method, telling your object to run the method you’d previously provided (in your case, updateLastTime:), and the timer passes itself as the argument to your method via the withObject: argument above. But what happens if you told the timer to use a selector that doesn’t take any arguments? Then when the timer calls performSelector:withObject: on your object (because the timer fired), your object doesn’t know what to do with the withObject: argument and simply ignores it. The result is that you can technically provide a selector with the wrong number of arguments and everything still seems to work. The selector you provide must still match the method that you actually implement, but this can take more or less arguments than what the NSTimer expected because of this quirk of performSelector:withObject: - that it quietly ignores extra arguments.

Why does performSelector:withObject: even exist? It’s one of a family of methods implemented in NSObject that exists for exactly this purpose - to allow an object to call a method whose name isn’t known until the program is running. When Apple wrote NSTimer, they didn’t know what method name you’d provide for the timer’s target. Telling an object to performSelector: is like saying “I’m pretty sure you have a method called ‘someMethod:’. Run it. And if I’m wrong and you don’t have a method with that name, just crash.” This is what the timer does - “I’m pretty sure you have a method called updateLastTime:. Please run it, with this argument: (self, the timer). If you don’t actually have that method, just crash.” So when you implement a method (and pass the selector) that takes no arguments - updateLastTime instead of updateLastTime: (the difference being the colon, which indicates an expected argument) - that’s when this “feature” of performSelector: causes everything to still work.

It’s very weird. This is a corner of Objective-C that you can get through most of your career without trying to really understand, because it’s not one we (as 3rd party developers) are really meant to be using. There’s a bit more on this in the book’s last couple chapters about KVO and the Objective-C Runtime.

That is pretty deep. Thanks for explaining.

When you say “your object”, as in

do you mean whatever instance of a class that has this initialization of NSTimer? In our case, that code is in main. So I am not sure if I know what “my object” is. Perhaps I am reading too much into that part.

Another thing I am not sure if I understand is what is meant by matching the method in

[quote]The selector you provide must still match the method that you actually implement, but this can take more or less arguments than what the NSTimer expected because of this quirk of performSelector:withObject: - that it quietly ignores extra arguments.

We are passing in a method to @selector, so how would we not match? As was mentioned, even if we implement updateLastTime (instead of updateLastTime:), we don’t see any problems. Is that a case of the selector not matching the method you implement?

Sure thing.

As to the first question, you make a good observation that the calling code is in main. I meant whatever object you have designated as the timer’s target. Usually this will be “self” if the calling code is in an object already. In this case, though, “your object” is the Logger.

To the second question, I mean that the selector that you pass into the timer initialization and the method that you implement must have the same name. updateTime: vs updateLastTime:, eg, as you’d expect. That’s all.

Ah. Of course. Thanks again.