Note that there are some explanatory texts on larger screens.

plurals
  1. POMessage forwarding does not work on particular messages
    primarykey
    data
    text
    <p>I've found out that some Obj-C messages do no get properly forwaded when an object does not explicity handle them.</p> <p>Here's an example:</p> <p>Create a new UITableView like:</p> <pre><code>UITableView *v ? [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 0, 0) style:UITableViewStylePlain]; </code></pre> <p>Then create an instance of an NSObject with the following methods:</p> <pre><code>(A) - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSLog(@"tableView:numberOfRowsInSection:"); return 1; } (B) - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"tableView:cellForRowAtIndexPath:"); return nil; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSLog(@"methodSignatureForSelector: %@", NSStringFromSelector(aSelector)); return [NSMethodSignature signatureWithObjCTypes:"@@:@"]; } - (void)forwardInvocation:(NSInvocation *)anInvocation { NSLog(@"forwardInvocation: %@", NSStringFromSelector(anInvocation.selector)); } </code></pre> <p>Let's call this object ds and set it as the dataSource for the table view:</p> <pre><code>v.dataSource = ds; </code></pre> <p>And when you run your code you should see that both methods (A) and (B) get called by the table view in the expected order:</p> <pre><code>LOG: tableView:numberOfRowsInSection: LOG: tableView:cellForRowAtIndexPath: </code></pre> <p>Now it will get interesting, try removing (or just change the name of) method (A), and you should get:</p> <pre><code>LOG: methodSignatureForSelector: tableView:numberOfRowsInSection: LOG: forwardInvocation: tableView:numberOfRowsInSection: </code></pre> <p>Which is fine because the table view tries to call the <strong>tableView:numberOfRowsInSection:</strong> and since the method is not there, the message gets forwarded to <strong>forwardInvocation:</strong></p> <p>Apparently, this is the default behavior for all messages that reference a method that is not defined at an object.</p> <p>However try restoring the (A) method and removing (B), and you should get:</p> <pre><code>LOG: tableView:numberOfRowsInSection: </code></pre> <p>... and an error telling you that <strong>tableView:cellForRowAtIndexPath:</strong> was called but didn't return a cell.</p> <p>For some reason <strong>tableView:cellForRowAtIndexPath:</strong> gets called (or not) but without following the expected <strong>forwardInvocation:</strong> pathway.</p> <p>Is this a bug?</p> <p>Am I doing something wrong?</p> <p>Are there some messages that explicitly do not get forwarded?</p> <hr> <p>Even though <strong>respondsToSelector:</strong> should return FALSE to both functions, somewhere in the implementation sends the message for <strong>cellForRowAtIndexPath:</strong> to some other object and breaks the default <em>expected</em> behavior...</p> <p>What I've learned is basically:</p> <p>If you are planning to respond to a message in your object, even through some implementation of <strong>forwardInvocation:</strong>, you should <strong>ALWAYS</strong> overload the <strong>respondsToSelector:</strong> method and return TRUE for all messages you plan to implement in your object.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload