I have a simple 4-tab UITabBarController
, with each tab consistent of a UITableViewController
. The first Tab is called Videos
, the second is Languages
, the third is Favourites
and the fourth is Leaflets
. The Videos
Tab contains a list of languages (about 6) and when a cell is clicked on, a segue
is performed to show the available videos of that language. The Languages
tab is a list of all Languages in the app. When a cell is clicked on, the available Leaflets and Videos for that language are shown. The Favourites
is populated using Core Data (I will come back to this) and finally, the Leaflets
tab is a list of languages; when you click on a language, you see leaflets available in that language.
The data, content of cells, the leaflets and the videos are all populated via NSMutableArray
s in the prepareForSegue
. The app is working very well.
With guidance from this question: Changing the UIImage of a specific UITableViewCell when an event occurs, I am able to tap on a cell in the Languages
tab and it does two things:
1) Adds a star UIImageView
to the cell
2) Adds the title of that cell to Core Data
The Favourites
tab is using NSFetchedResultsController
to populate it's UITableViewCell
s with the titles of the cells that have been favourited.
That part is working really well.
Issue
However, I would now like to implement consistency. What I mean by this is, if the user selects "English" in the Languages
tab and favourites a video called "3 Facts", when they go to the Videos
tab and click on English, the "3 Facts" cell
should have a favourite on it.
The Languages
tab is the only UITableViewController
that after showing the Languages, shows a UITableViewController
with sections with Leaflets on section 0 and Videos on section 1. If the user goes to the Videos
tab and selects a Language, it only contains one section.
This is the code that is currently doing the favouriting:
- (void)swipeableTableViewCell:(SWTableViewCell *)cell didTriggerRightUtilityButtonWithIndex:(NSInteger)index
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
CustomLeafletVideoTableViewCell *selectedCell = (CustomLeafletVideoTableViewCell*)[self.tableView cellForRowAtIndexPath:indexPath];
// We create a new NSString and assign it to the custom label's text (which is obtained from the cellForRow method)
NSString *cellTitle = selectedCell.customCellLabel.text;
NSLog(@"The text is %@", cellTitle);
NSManagedObjectContext *context = [self managedObjectContext];
NSString *key = [NSString stringWithFormat:@"%@_%ld_%ld", self.selectedLanguage, (long)indexPath.section, (long)indexPath.row];
if (self.favoritesDict[key] == nil)
{
self.favoritesDict[key] = @(1);
Favourites *favourites = [NSEntityDescription insertNewObjectForEntityForName:@"Favourites" inManagedObjectContext:context];
favourites.title = cellTitle;
}
else
{
[self.favoritesDict removeObjectForKey:key];
}
[[NSUserDefaults standardUserDefaults] setObject:self.favoritesDict forKey:@"favoritesDict"];
NSError *error = nil;
if (![context save:&error])
{
// Error
}
[cell hideUtilityButtonsAnimated:YES];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
The viewDidLoad
and viewWillAppear
contains:
if ([[NSUserDefaults standardUserDefaults] valueForKey:@"favoritesDict"] == nil) {
[[NSUserDefaults standardUserDefaults] setObject:@{} forKey:@"favoritesDict"];
}
// load favorites from user defaults
self.favoritesDict = [[[NSUserDefaults standardUserDefaults] valueForKey:@"favoritesDict"] mutableCopy];
The cellForRowAtIndexPath
contains:
if(indexPath.section==0)
{
customCell.customCellLabel.text = [NSString stringWithFormat:@"%@",[self.availableLeaflets objectAtIndex:indexPath.row]];
NSString *key = [NSString stringWithFormat:@"%@_%ld_%ld", self.selectedLanguage, (long)indexPath.section, (long)indexPath.row];
if (self.favoritesDict[key]) {
// show the favorite image
customCell.customCellImage.hidden = NO;
} else {
// hide the favorite image
customCell.customCellImage.hidden = YES;
}
}
else
{
customCell.customCellLabel.frame = CGRectMake(8, 20, 100, 40);
customCell.customCellLabel.text = [NSString stringWithFormat:@"%@",[self.availableVideos objectAtIndex:indexPath.row]];
NSString *key = [NSString stringWithFormat:@"%@_%ld_%ld", self.selectedLanguage, (long)indexPath.section, (long)indexPath.row];
if (self.favoritesDict[key]) {
// show the favorite image
customCell.customCellImage.hidden = NO;
} else {
// hide the favorite image
customCell.customCellImage.hidden = YES;
}
}
The NSString *key
has a role to play here because it is obtaining the correct section and row. When I copy this code over to the Videos
tab, the favourite does not exist on the same title that it does with the Languages
tab.
Ultimately, consistency is the important thing here. The user may favourite something from the Videos tab or Languages tab, but either way, the same "title" should be favourited in the other tab.
Update
Based on the comment of using NSUserDefaults, I have added some code. Firstly, in the LanguagesTab, I have added some code in the method that does the favouriting:
NSString *key = [NSString stringWithFormat:@"%@_%ld_%ld", self.selectedLanguage, (long)indexPath.section, (long)indexPath.row];
if (self.favoritesDict[key] == nil)
{
self.favoritesDict[key] = @(1);
Favourites *favourites = [NSEntityDescription insertNewObjectForEntityForName:@"Favourites" inManagedObjectContext:context];
favourites.title = cellTitle;
NSString *valueToSave = cellTitle;
NSLog(@"The valuetosave is %@", cellTitle);
[[NSUserDefaults standardUserDefaults] setObject:valueToSave forKey:@"starredName"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Back in the VideosTab
, in the cellForRow
, I have:
NSString *key = [NSString stringWithFormat:@"%@_%ld_%ld", self.selectedLanguage, (long)indexPath.section, (long)indexPath.row];
if (self.favoritesDict[key]) {
// show the favorite image
customCell.customCellImage.hidden = NO;
} else {
// hide the favorite image
customCell.customCellImage.hidden = YES;
}
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:@"starredName"];
if ([savedValue isEqualToString:@"# 3 The One Show"])
{
NSLog(@"Display star");
customCell.customCellImage.hidden = NO;
}
else
{
NSLog(@"Don't display star");
}
This works to some extent. For example, I selected a cell in the Languages tab called # 3 The One Show and when I come back to the Videos
tab, it does detect that in the if statement and it runs the NSLog to display a star. It then displays the star. However, the issue is, it shows the star on EVERY cell. I want it to only show a star on the cell that has the text "# 3 The One Show".
I tried:
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:@"starredName"];
if ([savedValue isEqualToString:@"# 3 The One Show"])
{
if ([customCell.customCellLabel.text isEqualToString:@"# 3 The One Show"])
{
NSLog(@"Display star");
customCell.customCellImage.hidden = NO;
}
}
else
{
NSLog(@"Don't display star");
}
This looks like it's working and now showing and not-showing the cell. However, this works with 1 value in the savedValue. In the cellForRow, if I have:
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:@"starredName"];
if ([savedValue isEqualToString:@"# 3 The One Show"])
{
NSLog(@"Display star");
NSLog(@"The cell is %@", customCell.customCellLabel.text);
if ([customCell.customCellLabel.text isEqualToString:@"# 3 The One Show"])
{
customCell.customCellImage.hidden = NO;
}
}
else if ([savedValue isEqualToString:@"Real Talk - Sangat TV discussion #TruthAbout1984"])
{
NSLog(@"Display the star yo");
NSLog(@"The title is %@", customCell.customCellLabel.text);
if ([customCell.customCellLabel.text isEqualToString:@"Real Talk - TV discussion"])
{
customCell.customCellImage.hidden = NO;
}
}
else
{
NSLog(@"Don't display star");
}
It only shows the star on the latest entry to the savedValue
NSUserDefaults
and because I have 1000+ entries, it won't be efficient to actually create different keys for each different entry, etc.
Now, because my Favourites
UITableViewController
is being populated by Core Data and the UITableViewCells are being populated by favourites.title
, could I do something with that? So, I already have the values of the titles that have been favourited, but isn't there a way to translate that in the Videos tab. Perhaps do a fetch request to get the titles, etc? I just need some guidance with this.
I have this code:
Favourites *favourite = nil;
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Favourites"];
request.predicate = [NSPredicate predicateWithFormat:@"title != nil"];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"title" ascending:YES];
request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSError *error = nil;
NSArray *favs = [context executeFetchRequest:request error:&error];
if (!favs)
{
NSLog(@"Nothing to see here");
// Handle Error
}
else
{
// If the object exists, just return it
// favourite = [favs lastObject];
NSLog(@"Number of objects %lu", [favs count]);
NSString *elements;
for (elements in favs)
{
NSLog(@"Elements %@", elements);
}
NSLog(@"Things to see here");
}
NSLog(@"The Favourites are %@", favourite.title);
This is more just stabbing in the dark though - I'm not sure how to return all of the objects of the Array and then to place the image on that cell with customCell.customCellImage.hidden = NO, etc.
Any guidance on this would be really appreciated.