Re: Getting started with Cocoa Bindings in My Project?
Re: Getting started with Cocoa Bindings in My Project?
- Subject: Re: Getting started with Cocoa Bindings in My Project?
- From: Ken Thomases <email@hidden>
- Date: Mon, 07 Sep 2015 22:53:40 -0500
On Sep 7, 2015, at 7:25 AM, Alex Hall <email@hidden> wrote:
> Sure. This is a Twitter app, which shows one type of tweet at a time. That is, the table can show one of home, mentions, DMs, favorites, RTs of the user, Twitter searches, tweets from a different user, etc. When an array is "active", right now it just shows its own tweets in the table, but I hope to do a bit more in the future, like changing the window title to show the tab's name. I'm just starting, so I know a lot of refactoring will have to happen; I'm in the "just get it working" stage.
>
> My class is TweetDataController, and it currently does *everything* that isn't related to my view. It holds my dictionary of tabs, but it also calls the Twitter framework methods to download new tweets, it posts tweets, it parses them for display, it replaces short URLs with expanded ones in tweet text… I know it's not good to have all that logic in one place, and I was going to refactor it soon, but as I said, I'm still getting things working and seeing how the app--and its internals--will evolve and need to be changed.
>
> Anyway, the idea behind the dictionary of arrays is that each tab (list of tweets) is an array of Tweet objects, and all the tabs are in the dictionary, accessed by String constants. For instance, when the user hits cmd-4 to show his favorites, the view controller calls TweetDataController.getTabByName(TwitterDataController.favoritesTabName). In the model, currentTab (a string) is set to the favoritesTabName string, and then the view controller reloads the table. Since the active tab has changed, reloading gets the array of tweets for favorites and my table shows favorites.
>
> I'm not bent on using this setup, it just made sense at the time, and I needed something. This is why I said earlier that I'm using a dictionary, but only need an array controller. It's also why I need that computed property, so that the controller is always pointing at the correct array. I see what you're saying, though: TweetDataController can implement the KVO-specific methods and expose only what it needs to, no need to worry about the active tab. As I said above, the model would then appear to the controller to just be a KVO-ready array.
I might suggest that you create a class named something like TweetStream. It would have a name property and a tweets property. The latter would be an indexed collection. It would be fine to back it with a mutable array, although the property's type would be immutable. Regarding the indexed collection accessors to which I've previously referred: you can, of course, implement the getter indexed accessors (-countOfTweets, -objectInTweetsAtIndex:, etc.), but you don't have to. Those accessors are a way of providing KVC-compliant access to an indexed collection property even when there's no actual array-typed object to return. They are completely general. However, when you do have an array-typed object to return, you can just implement a normal getter (i.e -tweets).
In Objective-C, you'd declare the property with type NSArray*, but you'd explicitly declare an instance variable of type NSMutableArray* to back it.
@interface TweetStream
@property (copy, nonatomic) NSString* name;
@property (readonly, copy, nonatomic) NSArray* tweets;
- (void)insertObject:(Tweet*)tweet inTweetsAtIndex:(NSUInteger)index;
- (void)removeObjectFromTweetsAtIndex:(NSUInteger)index;
@end
@implementation TweetStream
{
NSMutableArray* _tweets;
}
@synthesize tweets = _tweets;
@end
The property being read-only just means that there's no setter. It doesn't preclude you from adding mutating accessors. If you want it read-write, though, you can do that and clients will be able to directly set the tweets property. But, in that case, you have to implement the setter yourself because one synthesized by the compiler will do a -copy on the passed-in array, which will produce an immutable copy. You need it to do -mutableCopy so your internal array is always mutable.
I don't know what the Swift equivalent of all of this is. In particular, I gather that Swift doesn't allow for a distinction between the property and the instance variable, which is awful. I suppose you can define a private stored property of mutable type and a public computed property of immutable type. The computed property would just be a thin wrapper around the stored property. As we've been discussing, in order to maintain the KVO-compliance of the public property, all modifications of it must go through its accessors.
Anyway, your TweetDataController would have a number of these TweetStream instances. For now, it doesn't much matter if it holds them in a dictionary keyed by their names or in an array. (At a guess, I think you'll eventually want them in an array.)
Also, you have your read-only computed currentTweetStream property with the necessary KVO-compliance class method keyPathsForValuesAffectingCurrentTweetStream().
So, the array controller to serve the table view will be bound to some coordinating controller (likely File's Owner in a window or view NIB, AppDelegate in the MainMenu NIB). If that's the TweetDataController, directly, then the model key path would be "currentTweetStream.tweets". If it's some other controller, it might be a key path leading to the TweetDataController plus ".currentTweetStream.tweets". There would be no controller key. Controller keys are only used with binding targets which are mediating controller types known to Xcode, like NSArrayController, NSTreeController, NSUserDefaultsController, etc. For other targets, like your custom class, there's no controller key.
On Sep 7, 2015, at 9:47 AM, Alex Hall <email@hidden> wrote:
> Quick question on all this. I'm making my model a KVO-compliant class, just to see what'll happen. The Apple guide says to implement methods, all of which include <key>. I've replaced <key> with TweetsTab, such as countOfTweetsTab, and I added tweetsTab (note the lowercase t) to my array controller in the Attributes Inspector.
Hopefully, I've already answered the question you went on to ask, but regarding the above: on the Attributes inspector of an array controller, you describe the _elements_ of the array that the controller will be controlling. This stuff is basically optional when you're not using Core Data, but the Class would be Tweet (not TweetStream or TweetTab). The Keys would list properties of the Tweet class. So, tweetsTab would not appear there.
Regards,
Ken
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden