-1

I have an iPad app that uses a TabBar setup with a custom SplitViewController and allows selections from a standard left-hand table menu (controlled by a ViewController) to change the contents to the right (landscape only) controlled by a DetailViewController. This runs fine and is in the App Store. I am in the process of updating it to ARC and iOS7 using Xcode 5.1.1 and the conversion has worked and the program seems to run OK in the simulator. However I am getting a warning (which I never had before) in the didSelectRowAtIndexPath method of each of the Views. For example in a class, StylesViewController:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
   [(StylesDetailViewController *)detailViewController initWithIndexPath:indexPath];
   [((StylesDetailViewController *)detailViewController).masterPopover dismissPopoverAnimated:YES];
}

The warning is for the first line (the second is probably not used as the app only supports landscape) and is "expression result unused". The line is necessary, the program does not crash, so I assume that this warning could be ignored. However, knowing Apple, I would prefer not to submit an app with warnings for review. Can anyone suggest a harmless statment to 'use' the 'result of the expression' and hence silence the compiler?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
David
  • 1,018
  • 13
  • 22
  • That first line of code makes no sense. Why would you call an `init` method on an instance variable? A call to `init` should always be called with `alloc` to create a new instance of a class and the result should be assigned to some variable. – rmaddy Oct 19 '14 at 17:31
  • Not sure. I had standard code in the iPhone version of the app (which was my first app) but then had such trouble implementing tabbars in the iPad app version that I based my code the example of the guy who wrote the SplitViewController which worked. It's about a year since I did this so I'm pretty rusty. – David Oct 19 '14 at 17:39
  • But even if I assign the result to an id, I have no use for it, but I still need to do something with it to keep the Analyser happy (see comment to ctrahey below). – David Oct 19 '14 at 20:46

1 Answers1

1

Sending a message with the string 'init' in it's selector to an object that is not created on the same line of code is an important anti-pattern in iOS/Objective-C. The details are not entirely necessary, but the important (and relevant) bit of info is that technically an 'init' method returns an id, which is actually allowed to be a different object than the one that the message was sent to!

Your warning is simply telling you that you are not using that object. The calling of an init method outside of it's alloc line may have other unwieldy implications.

One caveat to this answer: The specifics will certainly depend on your implementations of the method in question, and posting that method (at least it's signature) will help. However, even if you are using that method to simply prime the object in a way that can/should happen over and over and apart from the alloc step, I highly encourage you to avoid the use of the string init in the name... I like to use loadWith... or something similar.

Chris Trahey
  • 18,202
  • 1
  • 42
  • 55
  • OK. The initWithIndexPath method (name used in book I learned from) passes the path so that the DetailView can find the stuff relevant to the row selected and display it. If I try the hack of assigning id foo to the line above and then foo = nil, the program runs and the "expression result unused" goes away. However running the analyser results in 'Dead Store' warnings (blue rather than yellow): "value stored in foo during its initialization is never read". Again, harmless, but do Apple's reviewers mind and does Xcode have a switch like Eclipse to make this sort of warning go away? Or what? – David Oct 19 '14 at 20:42
  • What I'm saying is to never call init anywhere besides exactly where you call alloc. If the information the object needs is not available when it is created, then make a different (not-init) method for giving the object it's required data. – Chris Trahey Oct 19 '14 at 21:42
  • But I'm not explicitly calling alloc anywhere. It would seem according to the http://stackoverflow.com/questions/13495464/ answer that memory is assigned by ARC and autoreleased in this kind of situation. Incidentally I can get rid of the warning by calling a doNothing method on foo. Horrible hack though. – David Oct 19 '14 at 22:47
  • Do you know how/when the detailViewController is created? My suggestion is to refactor a bit and create a method for e.g. `loadWithItem:`, then in the method shown in your question, fetch the actual object and pass it (not the indexPath) to your new load method. The load method should not return anything. – Chris Trahey Oct 20 '14 at 16:57
  • The detailViewController is a UIViewController which is an instance variable of the StylesViewController class (as it is synthesized in this class). Presumably the line of code in the didSelectRowAtIndexPath method casts it as a StylesDetailViewController and initializes it. The indexPath sent during the initialization is used assigned to a NSIndexPath in that class which is used in viewDidLoad to find and display the text and images appropriate to the selected row. Because the iPad version has a Split View it doesn't need to be pushed into view as in the iPhone version. – David Oct 20 '14 at 21:55