I was wondering if anyone has ever attempted to or thought of using the decorator pattern to make it easier to DRY up UITableView code.
What I'm thinking of is creating a set of reusable decorators for UITableViewCells, for instance one for adding background gradients, one for adding different shadings, and a variety of other stylings.
You would then be able to chain the decorators together, to get the desired effect, instead of having to bolt on some Frankenstein code to different objects every time you wanted to reuse similar design styles.
Does this make sense, or am I just recreating the wheel? I really dislike subclassing UITableViewCells, and think this would be a good way to get around that problem.
I'd love to hear the opinion of some of you guys who have way more Objective-C and UIKit experience than I do on this topic.
Isn't the decorator pattern typically based around an abstract base or interface/protocol at the root? Since your base here isn't exchangeable (it must be a UITableViewCell) this could be tricky.
Maybe you can pull it off by proxying, i.e. subclassing NSProxy to wrap a UITableViewCell. I don't know if that will work, as UIKit classes tend to be quite tightly integrated with one another. The proxy and the the real cell will have different identities, and if the cell sends messages to the table view with self as an argument, this could confuse the table view.
Another option is to subclass the table view cell once to add some kind of extensible delegate mechanism whereby you can dynamicall add delegates to each cell. I'm calling them delegates as they won't subclass from the table cell, just add a behaviour for it. You would then intercept messages to the cell and decide dynamically, based on the delegates present in the object, whether a delegate receives the message or whether it goes directly to the superclass (UITableViewCell) method implementation. You could define a protocol for each delegate which declares the new methods/properties the thusly extended cell will accept.
I don't know how much trouble this would be to implement in the first place, and how complicated the code for each delegate would be. I guess you'd have to try it to see if it's worth it in practice.
In any case, mixing in behaviours to UIKit classes would definitely be an interesting and useful thing to have. For my own apps, I've built an automatic view layouting system which lays out views depending on their content, the available space and certain resizing parameters. Something like this would probably reduce the amount of repeated code in that system somewhat.
While this approach is sound from an architectural point of view, in the reality of iOS it has a terrible effect on performance (it has been attempted before and did not end well). iOS caches pre-rendered bits of tableview cells as much as possible, so performing runtime modifications of the layout and appearance of different cells in a way that the designers of the UIKit did not anticipate would destroy that caching, and performance would suffer.
Take a look at how Matt Gallagher handles custom cell drawing, his approach has been pseudo-blessed by Apple at WWDC this year. Also, watch the "Tips and tricks to improve responsiveness" and "Understanding UIKit rendering" sessions from WWDC, as they address real world techniques for improving performance of UITableView.
Related
The UITableView can be used to create a list view if the at least the UITableViewDataSource is adopted by the relevant class. I have the below questions:
Why is it designed in such a way that based on the section and row , the controls are created through data source methods and given back to the UITableView instance. Why not provide all these information in UITableView instance with out using the UITableViewDataSource. What difference is it going to make?
EDIT1:
#hermann and #JOhn: You have mentioned that it breaks the MVC pattern. Let us assume I am creating a custom UITableView like control myself. I design it in such a way that I do not pass the data directly to the UITableView but instead I pass the relevant subviews that needs to be added in the rows and section and their relavant headers alone. I think this will not break the MVC..Am I correct? But still it has the problem that the current UITableView implementation style solves..the ability to reuse controls and images instead of bloating the memory usage.
First, doing so allows to stick on the MVC pattern. A UI object, meaning a view, should never directly communitcate with the model, wich is the business data. Plus it should not perform any business logic, which belongs to the controller.
Second, it is more flexible without the need of subclassing the UITableView object.
Third, the full concept is quite efficient from a performance and memory management point of view. Instead of loading all data upfront, that may be displied within a table, it can be fetched or calculated or whatever on a just in time "need to know now" basis.
Plus data containers, especially memory consuming once like images, can be released as soon as the data has been provided using the delegate/data source methods.
Of course, a subclass of UITableView could do the same in principle. I just doubt this would result in more maintainable code or even save any time or work resprectively.
If you don't want to stick with MVC, then feel free to subclassing the table view and hand all its data over in its init method or enable the table view subclass to load all that data from webservices or data bases or wherever it comes from.
And when you run into problems and get back to us searching for guidance, then be prepared for some nasty replies like "Why don't you stick to the established best practices or the MVC pattern?" ect.
In the event that your very table just displays some rather static values, such as if it just acts as menu for further navigation drill down etc. then this concept may look a bit rediculous. But it does not hurt either. And when it comes to more complex tasks of data providing then it certainly has its advantages.
Give it a chance. Give it a try!
For MVC you want to try to clearly separate what the model, controller, and views are responsible for doing. By allowing the view (tableview) to ask for the data from a delegate, the view can be create extremely generalized.
Using the delegate pattern, the controller can "stage" the data in anyway that is wants and then give it to tableView as the tableView needs it. The tableView doesn't care where the data comes, how it was transformed, what ADT is used, nothing. It is complete ignorant to where or what the data is. All it knows it should show this string at this location for this section and row.
I often get confused with when to use DataSource Pattern and when to use the Properties for providing configuration information to objects.
I have two ways to do this,
Generally I keep a lot of properties in the Object's class that has to be configured and a method that resets the object and continues with the new properties.
And the for the Object which is configuring the other object, I keep a method that with the name configureXYZ:WithValues: , which resets the properties and calls the reset method of the object to be configured.
This I have seen with MPMoviePlayerController, that we have to set properties.
and Other way is how tableView works, all the configuration information comes from datasource methods.
Can anyone throw more light on which way is preferred in which scenario.
Because Its often I feel tempted to use design patterns and make the code look stylish but I wanted to know when do we actually need these.
I am absolutely clear with delegate pattern and have to use it on regular basis.
DataSource was one thing I was never clear with.
When designing a class, the key factor you should consider when deciding between using a delegate or properties is how often the values can change. Properties work best if you will set the values one time and they should never change again. Delegates (of which datasource is just an example) work best if the values might change over time or change due to conditions.
For example, in UITableView, the number of rows is highly dynamic. It could change for many reasons outside of the control of the table view. What the rows even represent is highly dynamic. They might be data; they might be menu options; they might be pieces in a game. UITableView doesn't try to guess or control any of that. It moves it to a delegate (datasource) where potentially very complex decisions could be made.
MPMoviePlayerController has a few controls that mean very specific things and should almost never change (particularly once the movie starts playing). Basically you set the thing up, hit play and walk away. In that case, a delegate would likely be overkill.
There are many cases that are in the middle, and either way may be ok. I would encourage developers to consider delegation first, and then if it doesn't make sense go with properties. This isn't because delegation is always the right answer, but more because most C++- or Java-educated developers don't think in terms of delegation, so should make a conscious effort to do so.
Some other thoughts along these lines:
When using properties, it is ideal if they are configured at initialization time and are thereafter immutable. This solves a great number of problems.
If you find yourself needing a lot of properties, delegation is probably better and often simpler.
Delegate notification methods (somethingDidHappen:) are often better implemented as blocks. (Blocks are relatively new in ObjC. Many delegate-based Apple interfaces are moving to blocks, but you'll see a real mix out there for historical reasons.)
The difference between "delegate" and "datasource" is that a delegate manages behavior, while a datasource provides data. They are typically implemented identically.
It mostly depends on the dynamics of the class. UITableView is a very dynamic interface element. Its data comes and go. You can add/remove/edit/sort. You can interact with it. IF you assign properties to a tableView, it loses some of the properties that makes it as robust as it is. MPMoviePlayerController, on the other hand, has a different purpose. I have never used this class but by the looks of it, it reads one video file and provides playback. There is not many changes to it, so properties makes a lot of sense.
If you are writing a class, and you need that class to be as flexible as possible(UIPickerView, UITableView), having delegates allows you to do so. If your class only works with limited configuration after initialization, you could be better by taking the property approach.
For quite a while I've been looking at objective c examples, watching the Stanford lectures, and playing around with some code to get a hang of creating an iOS app.
However there are a few things that I can't find a good answer on:
How do I properly separate my layers? I understand the MVC structure, and I saw some examples of creating Categories for models to implement business logic. Is that the proper way, by enriching models or should I create dedicated classes (e.g. to authenticate users, extract models from json, group orders)?
How smart should views be? Can I make a view that displays a Contact (by assigning the contact property) or should I create separate properties for all of the Contact fields or should the view request it's information via a delegate call?
I'm using a Storyboard in my application. On my screen I want to
have a navigation bar, and let's say a view that displays orders. On
other screens I want to reuse the order-view.
How can I re-use the order-view's ViewController and View in other ViewControllers?
If I have 4 screens with the same look-and-feel, do I have to simply copy them in the Storyboard? This seems like a pain to main, what if I want to change my background? Or add a button to all of the views? When I create a setup-wizard I don't want to define the look-and-feel for every screen separately.
Coming from a C# background I probably have to get into the objective-c mindset :)
Any help on this would be great.
1) ObjC-Categories will easily distort your understanding of the main problem you're facing. ObjC-Categories are completely unnecessary. You could always approach these extensions by subclassing, object composition, additional methods in the actual model, or some customization in the controller or view. So if you need to format data (e.g. which is present in the model) for display in a view -- that task would often land in the controller. As far as the examples you provide: You may opt for models in simple cases -- as well, any of the examples could merit dedicated class, if complex enough or if it would keep you from redundant implementation. Note that these may be accessory classes, which simply produce a model, or they may be composites of multiple concrete of abstract classes. Not everything needs to land squarely in the definition of M-or-V-or-C. You're free to use many design patterns with ObjC. Think of MVC as the patterns Cocoa typically uses -- you will need to know them, and you will need to know how to subclass and extend these types, but these patterns lose dominance as implementations move away from Cocoa's libraries (e.g. as complexity increases).
2) They can be smart. However, under MVC, you want to focus its implementation on the view/presentation aspect. A view which represents a collection of information could in fact perform some tasks which are typically reserved for the controller -- however, you would generally cede that the implementation were a dedicated MONContactView in doing so. If you go that route, you would generally do so for easy reusability or to achieve a simple interface. Displaying information about a Contact could be very complex - In simple scenarios, these tasks are often handled by the controller. Specifically, a MONAwesomeContactView is likely less complex (e.g. in SLOC) than MONAwesomeContactViewController (unless you have some very special drawing or layout to perform). It would be more common to set the controller's contact, and let the controller push the contact data to the views' fields. Again, in the case of a very specialized subclass -- a view could very well hold its own controllers in some cases.
3a) There's nothing wrong with creating multiple instances of a class.
3b) No need to copy. When duplication is smelled, I push the implementation to actual code -- the programs can apply the look and feel you desire, or add or manipulate the subviews as you desire. Of course, they will not be present in Xcode's NIB editor. There are of course alternate approaches, but this replication often makes me move the implementation to compiled code. Achieving a good balance of both is not so difficult (personally, I do most of my views programmatically, rather than using NIBs).
This is a pretty abstract question and it's not clear what oh mean by 'layers'. Yes, you should create your own classes where appropriate, but categories also give you the option of adding functionality to existing classes. If you can be more specific with the question it'll be easier to provide a better answer.
It's a judgement call. If you want to create a view class that knows how to display an instance of your Contact type, that's fine in my book. If that view knows where Contacts are stored in the app, though, that's not so good.
Remember that the things in a storyboard are objects, not classes. You don't want to try to re-use a view from one scene in another scene -- that'd mean sharing a view between scenes, which really won't work. If you want to use the same order-view in several places, that'd be a good candidate for creating a class. On the other hand, you can set up your storyboard so that several different scenes all transition to the same scene. If you want different parts of your app to modally display a scene that displays an order, for example, you can do that.
I've created my first iPhone app that presents audio tracks of a similar genre in a tableview. The user can play audio tracks using ipod-like controls which streams mp3.
All of my code is in two main classes: RootViewController and CustomCell.
My RootViewControllerClass is massive. I'm assuming it is poor design to stuff almost all of my code in one class?
Initially, I thought it made sense because I only have one View Controller. To practice better coding conventions, I'd like to split up my RootViewController class into smaller, specific classes (assuming this is the correct practice?).
Here are the components of RootViewController that I plan to separate out into individual classes:
DataSource - pulls data from server; modifies and organizes the data for the tableView
TopChartsView - includes buttons in a view to modify the audio tracks(dataSource) by top rated weekly/monthly/all-time
GenreChange - includes buttons in a view to filter the dataSource by genre
AudioPlayerControls - includes buttons in a view that are similar to iPod controls
Am I organizing my classes correctly? It seems to make sense that I organize my classes by function. However, I'm having difficulty grasping how classes should interact with each other in an ideal design.
Do I use protocols and delegation to link my classes together?
Designing iOS apps is mostly about the MVC design pattern, which means that you seperate your model, view and controller. In your case I would put the DataSource logic in a seperate file or files (it's your model). This also makes it easier to reuse the same logic in another view controller in a later point. Maybe you can also subclass your UITableView if lots of code resides there.
Protocols and delegates are a great way to connect your classes and they are very frequently used in a good design. Since you don't have many viewcontrollers in your application (as far as I see), there are not very much opportunities to use them, please correct me if I'm wrong ;)
It's more about object-oriented-programming than especially about iOS and I think, you should get familiar with some concepts of OO-Design (if you really interested), but from my point of view you don't have to. To answer your questions first:
I'm assuming it is poor design to stuff almost all of my code in one class?
Some say so...
Am I organizing my classes correctly?
Hard to tell, by the information you gave.
Do I use protocols and delegation to link my classes together?
Not necessarily.
But: If your code works fine, you are the only one, who works on it, you don't plan to re-use your code as a library or by taking full classes from it (i.e. if you only plan to copy & paste), there is no need to refactoring everything just for the sake of doing it.
Even though: If you want to move forward or if you're planning to write libraries or something, it would be a good idea to learn about OO (sometimes it's even entertaining). Since you're working with objective-c this one from apple's docs could be a good start to learn.
And: If you read a bit about OO-programming and (more important) take the time and to read code of others, you'll know how and when it is useful to organize your own code.
Ok, this might not be possible, but I've got a class (called CompositeView) that's a subclasses UIView. It uses some core graphics work to produce a custom background based on some options. Not a huge class, but bound to grow as my demands change/increase/whatever. The problem I'm having is I use this class a lot, in a lot of different places. But in a few of the places I need it to be a subclass of UIScrollView instead of a UIView. Interestingly enough, I can simply change the superclass and it all works perfectly fine. But not only do I not want all my other views to be a UIScrollView, it also interferes with the operation of some of them. So I need a class that's sometimes a subclass of UIScrollView and sometimes a subclass of UIView.
For now, I've literally copied all of the interface/implementation of the CompositeView, changed the class name to CompositeScrollView, and changed it's inheritance to UIScrollView. It works fine, but now I've got two sets of code that do exactly the same thing, just inherited from different parent classes. This makes keeping them both up to date a pain.
Is there a better way to do this?
Single inheritance languages force you to use delegation. You'd factor out the added functionality into a separate class that you instantiate for your derived classes and then write forwarding shims from the derived class to the instances. It's painful.
Objective C has protocols which would describe the added functions (any shims that are not overrides) and then the compiler would error-out if you didn't write the shim ... which you still have to do manually.
Objective C also has categories that allow you to extend existing classes but these can't be shared (you have to extend each class individually) so it doesn't really help.
The best thing to do is impossible, of course: have a UIScrollView inherit from YOUR UIView subclass.
#smparkes' answer is good, but sometimes delegation does not do what you want, or it's too inconvenient. In this case, it's probably the latter.
Consider using the thing as a UIScrollView everywhere, but breaking the functionality that you don't need. UIScrollView instances act exactly like UIView instances -- well, they ARE UIView instances -- so you might just resolve this simple problem, "interferes with the operation of some of them" and go on your way. Shut off zoom, shut off scrolling, etc...
Unfortunately, this is the reality of single inheritance languages. Whatever you do, do not try to solve this with anything like changing the isa. Should you ever have any success, it will not be lasting. Objective-C is only slightly dynamic and does not allow for this kind of thing to be used seriously by regular programmers.
Ok, maybe this is totally crazy, but is ISA switching an option?
object->isa = [SomeClass class];
See: Objective-C: How to change the class of an object at runtime?
If you implemented a UIView-subclass that knew how to switch its ISA pointer to the UIScrollView-subclass, you would only have to deal with one class and could even decide dynamically which of the views you want at runtime.
Please note, that this is purely theoretical. I have never used ISA switching in live code and I personally don't think it makes for a good design :P
EDIT:
But again, it isn't reducing any redundancies ...
I've read a bit more into the topic and it really doesn't seem to be recommendable (memory structure of old object stays unchanged e.g.)
Yes, you may be interested in using Class-cluster. This can produce objects let's say MyCompositeClass which will produce either MyCompositeScrollClass objects or MyCompositeViewClass objects.
Apple uses class cluster a lot for instance in NSArray, when you use it, behind the scene your manipulating different objects. The difference is based on the size of the array, for instance for some small arrays NSArray will instanciate a class that is specialized in small data structure, etc...
This has the advantage of having nice performance and the complexity is totally hidded from the user by this concept of class cluster.
I invite you to read some documentation about that, it might be more understandable.
https://developer.apple.com/library/mac/#documentation/General/Conceptual/DevPedia-CocoaCore/ClassCluster.html
Hope this was helpful :)