I’m going to do two something that is considered bad style, but I have reasons, and I’m open to a Cocoa solution, I just don’t know what it is.
I want an NSArray which is type safe to a UIView, and then an NSArray which is type safe to arrays of UIViews. A 2D array of UIViews.
I’d like this because I’ve implemented a custom double UITableView which has a nested horizontal table view within a vertical table view. I would use my custom ViewsArray and Views2DArray as the data structure which other programmers easily give content to my DoubleTableView. Is that an adequate reason to want to extend NSArray?
The problem I’m having is that I’ve overridden the functionality of the method:
(NSArray *) initWithObjects:(id) firstObject ... as:
(ViewsArray *) initWithViews: (UIView *) firstView, ...
but the return value of my method is an NSArray, which does not have the other methods included in my ViewsArray, which means unrecognized selected exceptions. I’ve solved this temporarily by making a NSArray property of ViewsArray which has my views in it, but this makes for ugly code when I want to feed my content to my DoubleTableView.
Ex:
[[self.delegate content].arraysOfViews objectAtIndex:indexPath.section];
Instead of
[[self.delegate content] objectAtIndex:indexPath.section];
I know it’s a few letters, but I’m trying my best to write good code.
How can I return self in my initWithViews and have an NSArray with my added properties of greatestHeight, totalWidth, etc? (Casting?) Am I thinking about this wrong (with Java/typesafity …)? What’s the best solution for a data structure like this?
Edit:
To solve my problem in a way I deem “stylish”, I did the following:
This is my header (Notice it’s an NSObject):
@interface ViewsArray : NSObject
@property int greatestHeight;
@property int greatestWidth;
@property int totalWidth;
- (ViewsArray *) initWithViews: (UIView *) firstView, ...;
- (UIView *) getViewAtIndex: (NSInteger) index;
- (NSUInteger) viewCount;
@end
This is in my implementation:
@interface ViewsArray ()
@property (retain, nonatomic) NSArray *views;
@end
Which means I just manage a private NSArray. Allowing for pretty references.
What I learnt today: Read the damn documentation and embrace your language. I know this instance may not show that last one, but I’m closer 😉
Easy solution; don’t bother.
In using and debugging Objective-C apps using the NSArray/NSDictionary APIs for 18 years, I think I have run across wrong-class-in-collection problems only a few times. In all cases, it indicated an over-arching design issue, not a programmatic error.
Simply put, your app controls the contents of collections and, unless you stick the wrong thing in a collection, your collection will contain exactly what you expect. In a well written application, the number of places that might add something to a collection should be exceedingly small, typically only one or two spots.
If you do feel the need to be defensive against this, then add an
NSAssert([... isKindOfClass:...])at the one or two locations that add stuff to the array. No need to add the same at the points of retrieval.There is, however, a common false-positive failure mode that’ll appear to be an incorrect type in a collection. If you over-release an object and an object of some other class happens to be allocated at the same location, then you’ll see failures of this mode.