What's a good way for a class (that manages a list) to disseminate notifications?
I'm working on an iPad app has many pages for users to browse through. I'm implementing the functionality for users 开发者_如何学Pythonto 'favorite' a page so they can revisit it later.
I'm writing a Favorites class that will manage a list of the user's favorite pages. When a user presses the 'favorite' button, it will call either the addFavorite: or removeFavorite: method on the Favorites class. The input seems simple enough.
My question is: what's the best way to propagate that state-change event out to all my views? I have many redundant 'favorite' indicators scattered throughout the app, and they all need to be kept in sync. For instance, if the user favorites Pink Floyd in one view (changing the star from gray to yellow), all the other views that link to Pink Floyd need to display yellow stars next to the link instead of gray ones.
It's my understanding that there are lots of ways to do this using Objective-C notifications. I'm just looking for a clean and maintainable one. What has worked for you in the past? Thanks for your time.
Check up on NSNotificationCenter
and NSNotification
. I use notifications quite regularly especially if there is more than one party interested in the shared information making the delegate pattern difficult. The main issue with notifications I've run into is when subscribing UITableViewCell's to a notification: avoiding that dequeued cells respond to the notification.
Here's the code I ended up writing using NSNotificationCenter and a UITableView for bonus points. Maybe it will serve to help someone else.
In the Favorites class:
+ (void)toggleFavorite:(NSString *)artistName {
if([favorites member:artistName]) {
[favorites removeObject:artistName];
[[NSNotificationCenter defaultCenter] postNotificationName:@"favoriteRemoved"
object:artistName];
} else {
[favorites addObject:artistName];
[[NSNotificationCenter defaultCenter] postNotificationName:@"favoriteAdded"
object:artistName];
}
[[UserLibrary current] verifyLibrary];
}
One of the 3 views that interacts with the favorites: a table view, where each cell has a star:
// register for notifications
- (void)awakeFromNib {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(favoriteAdded:)
name:@"favoriteAdded"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(favoriteRemoved:)
name:@"favoriteRemoved"
object:nil];
}
// search through visible cells for the one that needs to be starred
- (void)favoriteAdded:(NSNotification *)notification {
NSString *artistName = notification.object;
for(ArtistTableViewCell *cell in [(UITableView*)self.view visibleCells]) {
if([artistName isEqualToString:cell.artistLabel.text]) {
cell.starred = YES;
}
}
}
// search through visible cells for the one that needs to be de-starred
- (void)favoriteRemoved:(NSNotification *)notification {
NSString *artistName = notification.object;
for(ArtistTableViewCell *cell in [(UITableView*)self.view visibleCells]) {
if([artistName isEqualToString:cell.artistLabel.text]) {
cell.starred = NO;
}
}
}
// when cells are created or reused, make sure the star is set properly
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ArtistTableViewCell *cell = ...
NSString *name = ...
cell.starred = [Favorites isFavorite:name];
return cell;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
The table's cell. Notice how the cells receive events from the TableView so they don't have to register for notifications (and risk being notified after being dequeued).
- (IBAction)starPressed:(id)sender {
NSString *name = artistLabel.text;
[Favorites toggleFavorite:name];
}
- (void)setStarred:(bool)isFavorite {
UIImage *img;
if(isFavorite) {
img = [UIImage imageNamed:@"filledstar30px"];
} else {
img = [UIImage imageNamed:@"emptystar30px"];
}
[favoriteButton setImage:img forState:UIControlStateNormal];
}
精彩评论