iPing example questions


#1

thanks for a great book. I’ve been jumping around it a bit because I have a command line wrapper project that can’t wait for me to become an expert via the academic process. If I missed something obvious in a previous chapter just point me in that direction.

in the iPing example it was the first time I saw outlets declared like instance variables. I didn’t quite understand that. I must have missed something eariler?
also - the 2 notification methods (dataReady and appendData) were not defined in the .h file and the debugger didn’t complain - is that simply because they were defined as selectors when creating the notification object?

A quick comment from a newbie on testing the status of the NSTask object when its running. In the startStopPing method the comment says “Is the task running” and it’s tested like this “If (task)” … and later in the dataReady method the same comment and syntax is used again.

But in reality is the “if(task)” syntax really checking if the task is running or rather testing if the object is not nil or zero? I don’t fully understand the “if (task)” type syntax when task is an object. it just means its not nil or not zero as in the other example in the script “if ([d length])” ?

I found you can test if a task is really running like this “[task isRunning]”. Which seems to work nicely in the startStop method. When I changed to this syntax in the dataReady method, I lost my last and final data read. So in that method it looks like we are not really testing if the task is running but rather testing to see if the object has been torn down by the taskTerminated notification method. Because of the buffers in NSPipe, it will still retrieve some data after the task stops so we need that final call to flush the pipe. here is an example of my NSLogs (note the last read after the program stopped):

2012-01-08 18:08:59.138 iPing2[84425:707] dataReady:61 bytes
2012-01-08 18:09:00.139 iPing2[84425:707] dataReady:61 bytes
2012-01-08 18:09:02.084 iPing2[84425:707] task completed or was stopped with exit code 0
2012-01-08 18:09:02.086 iPing2[84425:707] dataReady:168 bytes
kill
quit

I made a couple of syntax changes that are clearer to me at this stage of learning so I thought I’d pass it along as an optional syntax for others in the learning process like me. If you change the syntax in method startStopPing to look like this it may be easier to understand.

if ([task isRunning]) {
[task interrupt]
}
else { …

and in the dataReady method use this:
if ( task != nil ) {
[[pipe fileHandleForReading] readInBackgroundAndNotify];
}


#2

Using instance variables as outlets is something of an older practice, but still perfectly valid. More often than not there’s no need for a full property for an outlet, so we use the instance variable directly in cases like this.

Regarding testing if the task is running: in this case we are taking advantage of how taskTerminated: sets task to nil. So yes, we’re implicitly testing “if (task != nil)”.This is pretty commonplace in C (and C++).

Sounds like you ran into some subtleties in how -isRunning works, but otherwise I think that’s a reasonable approach.

Adam


#3

thanks for the quick reply. could you clarify my question on the selectors / methods (dataReady and taskTerminated)? do they need to be defined in the interface section? In the example they are not defined in the interface but called out when the notification add observer is created and defined as methods in the implementation area.


#4

Declaring a method in the header file is optional. Technically, because Objective-C uses actual message passing, no methods need to be declared. However, the compiler helps us avoid sending unrecognized messages (selectors) to objects by flagging these as errors. It uses declarations (in header files and anonymous categories) to assemble a list of known selectors, but it will also notice if a method is defined before it is called later in an implementation file, and treat that as an implicit declaration.

The reason that these two methods are not declared in the header file is that they are private (outside classes have no need to know about the existence of these methods), and because the compiler does not check when we use @selector(…) to reference a selector (since these methods are both being used as notification actions). Declaring a method in a header file does not change the object code generated by the compiler, it helps in identifying programming errors and facilitates autocompletion.

That was fairly technical, but does it help?

Adam