I'm creating an app that has a master-detail interface, similar to iTunes. It has the same data hierarchy as iTunes' playlists (except that I'm not allowing groups of "playlists" to keep things simple). In other words, there are normal playlists where their only items are added manually by the user. There are smart playlists, which show all items that match a user-defined predicate. Finally, there are some "playlists" that are not editable at all by the user (I call these DefaultFolders), but are in essence nothing more than fancy smart playlists in that their predicate is to show everything. These are like the "Library" and "Movies" sections in iTunes.
In my attempt to recreate this structure, I've come up with the following hierarchy (in Core Data): http://gallery.me.com/davedelong#100084/Screen%20shot%202009-11-07%20at%207.17.53%20PM&bgcolor=black (hopefully it is self-explanatory)
However, as I've gotten further into this app, this structure has become a little cumbersome. For example, I defined an accessor on the AbstractFolder class called -(NSSet *)items, so that all concrete folder types (DefaultFolder, SmartFolder, and Folder) can easily retrieve their contents. This coincides with the relationship that the Folder entity has with the Item entity. However, I can't implement the items accessor in AbstractFolder, because that would override the generated accessor provided by Core Data for the Folder entity. I've thought about making it part of a protocol that all concrete folders would implement, but that seems to defeat the purpose of inheritance.
So I open this up to the collective wisdom of the mailing list. Is there a better way I could model this structure? Have any of you worked on apps with similar structures? What did you find helpful?
Sorry, I haven’t used Core Data that much, but it’s not clear to me why you need to implement the items accessor in AbstractFolder? Can’t you just stick it in a category in the header and not bother to implement it? This is the standard approach for abstract methods.
For example, in AbstractFolder.h, you’d have:
#interface AbstractFolder (Abstract)
NSSet *items;
#end
and then you don’t bother to implement it anywhere—which will force the subclasses implementation to be used.
I've come up with a structure, which I detail in this answer: https://stackoverflow.com/questions/1812311#1812924
Related
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.
I've been dealing with Core Data for the first time and I wanted to know what the best practices are for extending the classes that Xcode generates for my NSManagedObject entities.
I saw mogenerator and I've been also using a similar approach to that as suggested in SUPER HAPPY EASY FETCHING IN CORE DATA.
So I had three kinds of classes:
The EasyFetching category (only one class);
A generated NSManagedObject subclass (i.e.: _Entity);
A custom subclass with some custom methods like finding all the inactive objects, clearing the cache for an object, etc. (i.e.: Entity).
This approach let me do some custom code while I could refactor my Core Data entity and generate it as many times as I needed. But I've also run into some problems like not being able to declare object level methods for my entities (because the NSManagedObjectContext only knew my _Entity classes).
Now I'm using categories to extend my entities functionalities. And this works a lot better because I can have custom object level methods. I now have three kinds of classes:
The EasyFetching category (as it has a lot of methods that all my custom code uses);
A generated NSManagedObject subclass (i.e.: Entity);
A custom category for my NSManagedObject entity (i.e.: Entity+Custom.h).
My question is: what would you recommend?
Thanks in advance for your answers
Now that you have posted your question as an answer on my question,
I thought I should answer your question :)
Mogenerator doesn't look bad, give it a try.
Also the way you suggested with categories is also a fine option.
Infact here is a link that exactly explains How to do so.
I’m fairly new to OO. If I have two classes A and B that need to exchange data, or call each other’s methods, I need to be able to access an instance of class B from class A. Should I maintain the address of the instance object in a global variable? Should I appoint a (singleton) master class, and make (pointers to) instances of A and B properties of the master class? (AppDelegate comes to mind.)
Is there a straightforward by-the-book way to implement this? Somehow I‘m missing some "best practice" here. I’ve looked through Apple's examples, but didn't find an answer.
EDIT: Since I'm fairly new to MVC design patterns, my question is essentially "Who creates who"?
We're talking about an Audio Player here. 1. When the user selects a song, the UI displays its waveform by creating a viewController which creates the appropriate view. 2. When the user hits play, the UI displays a timeline while the song is playing by overlaying a new view over the waveform. Now, the latter view needs some info from the waveform display viewController. Right now, I'm storing a pointer to the viewController in an instance variable of my appDelegate. This works, but feels extremely strange.
Should I outsource the info that is needed by both classes to some third entity that every class can access easily?
Classes aren't simply departments of code. They are templates for the creation of objects, which you should think of as actors in your program, doing things within their areas of responsibility (which you define—you decide what each object does) and interacting with each other.
While you can handle a class as you would an object, classes generally do not talk to each other. Most of the time, you will create and use instances of the classes—which is what we normally mean by “objects”—and have those talking to each other. One object sends another a message, telling the receiver to do something or changing one of the receiver's properties. These messages are the interactions between your program's objects.
Those weird expressions in the square brackets are message expressions. Nearly everything you'll do with a class or object will involve one or more messages. You can send messages to classes the same as to objects, and classes can send messages just as objects can.
In Cocoa and Cocoa Touch, you typically have model objects, view objects, controller objects, data objects (such as NSString, NS/UIImage, and NSURL), and helper objects (such as NSFileManager). The classes you'll write for your application will mainly be model, view, and controller objects (MVC). The model represents (models) what the user will see themselves manipulating; the view displays the model to the user; the controller implements logic and makes sure the model gets saved to and loaded from persistent storage.
For more information, see Object-Oriented Programming in Objective-C and the Cocoa Fundamentals Guide.
Since I'm fairly new to MVC design patterns, my question is essentially "Who creates who"?
Controllers create and load the model, and load the views, and pass the model to the view for display. Certain controllers may also create other controllers.
It's good to keep a straightforward tree-like graph of ownership from a single root of your program—typically the application object—down through controllers to leaf objects in the models and views. If two objects own each other, that's a problem. If an object is not owned by anything outside of its own class (a singleton), that's usually a problem as well—a sign you need to think some more about where that code belongs. (Helper objects are the main exception; most of those are singletons. Again, see NSFileManager for an example. But they are few and far between.)
Further situation analysis require more information. At first place you should more specify the relation between classes and what exactly do you mean by exchanging data.
Singletons should be generally avoided. If you want to exchange information it is usually sufficient to provide for example instance of the class A to the instance of the class B by some method or constructor. The instance of B is then capable of calling public methods (and accessing public properties) of the instance of A.
A little bit of "best practices" can be learn by searching up "Design Patterns".
You should decide if one class can be an object of another class (encapsulation), or if one class can inherit from the other class (inheritance). If neither of these is an option, then maybe you could make one class (or some of its members) static?
Thanks for your contributions. Additionally, I found information on this page very useful. It lays out MCV considerations for cocoa in a hands-on way and practical language.
I've recently discovered categories and was wondering when it might be appropriate to use them in a user defined class/new class. For example, I can see the benefits of adding a category to an existing class like NSString, but when creating a new class what would be the advantage of adding a category to this rather than just implementing a normal method?
Hope this makes sense.
Many thanks
Jules
The answer isn't really any different for your own classes than it is for framework classes. If you have multiple projects, you'll likely end up sharing some classes between them. However, you may want to extend some of your classes so that they work more easily with a specific project, but not want to include those extra methods in your other projects, where they might not make sense. You can use a category to extend your class without needing to subclass.
If I understand your question correctly, creating a "new class" is always "subclassing" because you're subclassing NSObject at the very least.
You could use categories on a new class to separate out sections of responsibility of a complex class. For example, all the basic functionality (instance variables, accessors, description, etc.) can go in one file (the "main" class file) while all methods to support a protocol (such as NSTableViewDataSource) can go in another.
Some take this approach to keep things "neat". I'm a firm believer in "if it's my own custom class, all its code should be in one file" so I do not personally do this. I demarcate different logical aspects of the class' code with "#pragma mark Some Section Name" to help navigation and readability. Your mileage may vary.
Adding a Category on NSString is useful when you want to call a method on every single NSString instance you will encounter. This is a real improvement over inheritance for this kind of object because they are used by the core framework and you don't have to convert a NSString object to your subclass when you want to call your custom method.
On the other hand, you can just put methods in, no instance variables.
In the book Refactoring by Martin Fowler, he has a section titled "Introduce Foreign Method" (A server class you are using needs an additional method, but you can't modify the class.) That's what categories are good for.
That said, there are times when using a category, instead of changing the class, is appropriate. A good example on using a category, even though you could change the server class, is how Apple handled the UIViewController MediaPlayer Additions. They could have put these two methods in UIViewController itself but since the only people who would ever use them are people who are using the Media Player framework, it made more sense to keep the methods there.
I am a great fan of code generation (from UML) and coming from the Java world, I wonder how I would implement automated bi-directional association management in Objective-C.
Image an association Partner <-> Address, one-to-many and navigable from both ends. What I would like to achieve is that if I append an Address to a Partner that Address object should automatically know about its Partner.
So the implementation pattern would be to have an NSMutableArray* on the Partner side and a Partner* on the Address side. The property on the Address side is easy to implement, as a setPartner:(Partner*)aPartner could automatically insert the Address (self) into the Partner's NSMutableArray managing the addresses. The other side, however, is not so easy to implement. The standard implementation pattern for to-many references in Objective-C seems to be the NSMutableArray obtainable via the get method of the #property. The object in possession of this NSMutableArray could then insert an Address object into the array, which would of course not be updating the other side.
I know that there are other patterns for this kind of association management, for instance, via addTo...() and removeFrom...() methods. But I don't know yet if this would fit with other principles of Cocoa programming or even prevent me from using Cocoa efficiently. I am thinking about Interface Builder here. Not much experience, but I have seen something called an ArrayController which seems to be quite handy but which also seems to expect an NSMutableArray type property to work with. And if this guy inserts objects into the array I need to intercept that and make the other side adjustment.
As a Java programmer I would tend to subclass NSMutableArray now and override some of its methods which could then manipulate the other end. Would this be possible at all? I read about categories but so far I have understood that I could only add methods to a class this way and not override them nor add to the structure of it. Or should it be method forwarding? I am confused right now. If you could point me into the right direction of thinking it would be so great. Thanks a lot!
Welcome to Cocoa. Do not subclass built-in collections. You will go insane.
Allow me to clarify: in Cocoa, we have these things called "Class Clusters". Clusters are a hierarchy of private classes that all have a common, public superclass. In this case, NSArray is the public superclass, and there are private subclasses that are the actual array implementations. This presents a really difficult challenge when subclassing, because you don't know what class (or classes) you would need to subclass.
The common work-around is to create a new NSObject subclass that "wraps" an NSArray (ie, it has the array as an instance variable ["field"]), and then you invoke methods on the custom wrapper, and the wrapper holds all the custom logic you need.
As to answer your question, I've found that when I have this sort of set up where I need to maintain one-to-one, one-to-many, or many-to-many relationships automatically, there's nothing that beats using CoreData. CoreData is a built-in framework that's more or less like an object store. One of the truly awesome things that it does is handle relationship integrity, which is what you're looking for.