Silver Challenge...Help a lost sheep


#1

I’m working on the silver challenge and am having a mental block of what I am actually supposed to be accomplishing. My first speed bump is that the methods in the ItemsViewController must be know beforehand in order to send a message to it, doesn’t it? If so, then how generic can the base class method be? If it is creating this dynamically, then the method in the controller would be determined by the base cell subclass.

I also thought that I could create a a class method to create the selector similar to the randomItem class method.

In the end, Im basically just kind of lost as to what the functionality is supposed to do. Someone kind enough please help.

Thanks,
Jeff


#2

OK, I’ve decided that the what I am supposed to do is to create a method in the base class that at a minimum creates the selector from the sender (button or steeper in these tests). I would call this method from the subclassed implementation with the appropriate, necessary, variables. Is this correct?

If true, next question: Is it OK, or proper, to actually send the message from the super class to the controller rather than passing the created selector back to the subclass and then sending the message to the controller from there? Seems needless to do so when I can just send the message from the super.

Jeff


#3

I’ve created a solution that seems to be working. Hopefully someone will respond with comments. I’ll post the code if you want. Basically, what I did was to create the selector string in the subclassed cell along with an NSArray. This array holds the variables/objects needed in the method in the final method call. I really didn’t like the NSInvocation idea so went with this way instead.

Would love some feedback.

Jeff


#4

We are all here Jeff, and we want to see your code.
donPiter used the “NSInvocation” class but you didn’t like that approach.
I want to see different solutions so I at least can understand what we need to do and why we need to do that.

Let’s brake down this challenge on simple logical steps.Think with me together guys and gals and contribute alongside.
Currently I understand that we need to:

  1. Create a subclass of UITableViewCell - a “base” class;
  2. Give it an ability to forward action messages to its controller;
  3. Make HomepwnerItemCell (HIC) a subclass of that “base” class;
  4. Create another UITableViewCell that will be a subclass of that “base” class that should have a UIStepper that will adjust the value of BNTItem.

To tackle this challenge, we need a clear understanding what we already have.

  1. We have a UITableViewCell subclass - HIC that represent a view of a cell from which our table is constructed. It is not a controller, but a simple view class (UITableViewCell is a subclass of UIView). We use this class to create cells for our table in our ItemsViewController class in method : "tableView: cellForRowAtIndexPath: "

  2. As we remember - every view class suppose to have a controller. ItemsViewController (IVC) class is a controller to HIC.
    Our HIC has a thumbnail of BNRItem’s image. When tapped it reveals a full size image in a stand alone view- a view of class ImageViewController.
    When a thumbnail is tapped, HIC is being sent message "showImage: ". But since it is a view object - it can’t handle any operations with “Model” objects (it doesn’t have access to images). View objects suppose to pass any action messages to their controllers. Therefore, in HIC’s , method "showImage: " we doesn’t perform any real “image showing”. Instead we create a selector to specify which controller’s method should be send instead. We want IVC’s method "showImage: atIndexPath: " to perform the “image showing”.

That’s what we have so far.

Now our challenge.
It says that cells often need to pass action messages to its controller. Therefore we are asked to create a “base” class that will pass all action messages to the controller, and therefore its subclasses will inherit that and we won’t need to write code similar to what we’ve written in HIC "showImage: " method.
Is my logic right so far Jeff?
My problem is - even after braking down everything step by step, I have no clue what methods and properties our “base” class should have.


#5

Sure. Let me find the solution and I’l post it. However, I’ve done a lot of programming since then and may be embarrassed by what I did.


#6

Thanks, Jeff for your reply.
True, you were going through that chapter back in June. Have you finished book yet? My deadline is the end of this year (2013) but I still have 300 pages. Just wondering how others are doing.

About this particular challenge - I digged through this thread: viewtopic.php?f=227&t=4064 and found Nerburikun’s solution to be the most elegant and easy to understand. He also didn’t use “NSInvocations”.

For those who came here to check for solution or explanation - I will soon post here step-by-step solution and logic for this challenge. Let me just finish with that UIStepper.


#7

Check Nerburikun’s solution in this thread: viewtopic.php?f=227&t=4064
Here is explanation of his solution. (Please don’t mind my grammar)

So now we have following structure:
1. We have a table - ItemsViewController(IVC). That table is constructed from cells using method: "tableView: cellForRowAtIndexPath: ".

2. We wanted our cell to be custom so we created a custom class of type UITableViewCell - "HomepwnerItemCell" (HIC). In that custom class we have a property UIImageView *thumbnailView that represents a thumbnail-button that show image of BNTItem. Since that image pops out in a new "popover" view - we also created a separate UIViewController for it - ImageViewController. 
We had problem, because an HIC had to have access to images to fill the view of ImageViewController when the thumbnail button was clicked. But HIC is a "view" object, not a "controller". Therefore we wrote a method for the HIC so that it simply passes to HIC's controller, which is IVC, what method should be implemented. 
Now, that was a good solution, but what if we have another cell that also want's to pass a method to its controller? We would have to implement similar code in that cell. And that will happen for every cell. 

Instead of doing that, we create another class type of UITableViewCell that will be the “base” class. That “base” cell class will take the role of passing/forwarding methods from cells to controller, so that cell classes don’t need to do that every time.

Back to the code.
3. In the "tableView: cellForRowAtIndexPath: " method we create an instance of HIC class and call it “cell”.
We set properties of the “cell” such as: nameLabel, serialNumberLabel, valueLabel, etc., Every HIC objects has these properties. We list them in HIC.h file.
Because HIC is a subclass of our “base” class BNRCellBase, HIC objects also inherit properties from its parent class. In BNRCellBase we also has properties “controller” and “tableView”, therefore, HIC objects also has them. We set them too.

4.We created our HIC object and one of its abilities is when a thumbnail is pressed, it will show us an instance of ImageViewController (with an image of BNRItem inside). That ability to show images is possible because of method "showImage: " that we implement in the HIC.m file. When a thumbnail is pressed, the "showImage: " is sent to the instance of HIC. What’s happening inside that method? Inside we send following message:

  1. -that isn’t a standard method and we suppose to implement it somewhere in the HIC.m file. But we don’t have it there. When a compiler can’t find a method in the .m file - it goes to class’s parent class and looks inside his .m file. HIC’s parent class is our “base” class - BNRCellBase class. Its .m file implements that method:
  1. Inside of the implementation we take method that was passed as an argument ( (SEL)act ), which is in our case was "showImage: " method from HIC.m. We convert name of that method to a string so that we can modify it a little and add "atIndexPath: " to the end. Index path is necessary to specify the address of that cell in the table. We convert the string back to a method and send that method to the controller (IVC):
  1. In the controller’s .m class (IVC.m) we suppose to implement a method that was passed from the method “actionSender:(SEL)act fromObject:(id)obj”. It should append on "atIndexPath: " to be coherent with previous step (we already wrote its implementation)

Hope it was helpful to you.