Bagaimana mempersiapkanForSegue dengan penelusuran NSFetchedResults ke tampilan tabel lain dengan tujuan c

Saya tahu mungkin ada solusi yang sangat sederhana untuk ini. Saya menggunakan contoh apple iphoneCoreDataRecipes. Saya mencoba menelusuri dari tabel awal (RecipeTypeTableViewController) dari RecipeTypes (yaitu Minuman, Makanan Penutup, Hidangan Utama) ke tampilan tabel berikutnya dengan daftar jenis Resep tersebut (RecipeListTableViewController). Saya membuat kelas baru RecipeType, berpikir saya bisa menggunakan ini untuk mengembalikan resep dari RecipeType yang dipilih. Sejauh ini hal terbaik yang bisa saya dapatkan adalah mengizinkan pemilihan tetapi menampilkan daftar semua resep yang sama. Kode asli dimulai dengan RecipeListTableViewController menggunakan NSFetchedResults untuk menampilkan semua resep. Sekarang saya memiliki tampilan awal RecipeTypes tetapi saya tidak yakin bagaimana cara meneruskan tipe yang dipilih ke RecipeListTableViewController. Saya perlu mengubah RecipeListTableViewController untuk menampilkan daftar RecipeType yang dipilih tetapi saya tidak yakin bagaimana menerapkannya. Saya rasa pada dasarnya saya ingin meneruskan NSMutableArray dari hasil yang diambil ke tampilan tabel lain tetapi tidak yakin arah mana yang harus diambil. Dan saya tidak ingin mengacaukan tindakan kerja lainnya di RecipeListTableViewController, yaitu mencari dan mengedit resep. Berikut gambar tindakan tabel sejauh ini [RecipeTypeTableView][1] & [RecipeListTableview][2]. Terima kasih sebelumnya atas saran apa pun.

Menghapus ini

File: RecipeType.h

Berkas: RecipeType.m

Saya menggunakan tipe NSManagedObject *dari Kelas Resep NSManagedObject saya untuk membuat tampilan awal jenis resep (Pembuka, Bev, dll.) di RecipeTypeTableViewController -

File: Resep.h

@interface Recipe : NSManagedObject
@property (nonatomic, strong) NSManagedObject *type;

Berkas: RecipeTypeTableViewController.h

//  RecipeTypeTableViewController.h
//  Recipes
#import <UIKit/UIKit.h>
@interface RecipeTypeTableViewController : UITableViewController <NSFetchedResultsControllerDelegate>
@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) NSManagedObject *type;
@end

File: RecipeTypeTableViewController.m - bagian persiapan untuk segue

#import "RecipeTypeTableViewController.h"
#import "Recipe.h"
#import "RecipeListTableViewController.h"
@interface RecipeTypeTableViewController () <NSFetchedResultsControllerDelegate>
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
@end

@implementation RecipeTypeTableViewController

static NSString *MyIdentifier = @"showRecipes";

- (void)viewDidLoad {
[super viewDidLoad];
// register this class for our cell to this table view under the specified identifier 'ARecipeType'
self.title = @"Category";
//[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"ARecipeType"];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangePreferredContentSize:)name:UIContentSizeCategoryDidChangeNotification object:nil];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;

// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {

    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    //abort();
}
}

- (void)viewWillAppear:(BOOL)animated {

[super viewWillAppear:animated];
self.title = @"Category";

}

- (void)didChangePreferredContentSize:(NSNotification *)notification
{
[self.tableView reloadData];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIContentSizeCategoryDidChangeNotification object:nil];
}
#pragma mark - Table view data source

//- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
//#warning Incomplete implementation, return the number of sections
//return [[self.recipeTypeFetchedResultsController sections] count];

//    return 1;
//}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Number of rows is the number of recipe types
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
//return self.recipeTypes.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ARecipeType" forIndexPath:indexPath];

// Configure the cell
NSManagedObject *recipeType = [self.recipeTypes objectAtIndex:indexPath.row];
cell.textLabel.text = [recipeType valueForKey:@"name"]; 
return cell;
}

#pragma mark - Fetched results controller

- (NSFetchedResultsController *)fetchedResultsController {

// Set up the fetched results controller if needed.
if (_fetchedResultsController == nil) {
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"RecipeType" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];
    NSLog(@"Setting up a Fetched Results Controller for the Entity named %@", entity);

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

    [fetchRequest setSortDescriptors:sortDescriptors];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Recipe"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;


    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error])
    {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    }
}

return _fetchedResultsController;
}

#pragma mark - Navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:@"showRecipes"]) {
    NSLog(@"Setting RecipeType for the RecipeListTableViewController");
    NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
    Recipe *selectedType = [self.fetchedResultsController objectAtIndexPath:indexPath];
    RecipeListTableViewController *recipeListViewController = segue.destinationViewController;
    recipeListViewController.type = selectedType;
    recipeListViewController.managedObjectContext = self.managedObjectContext;
}
}

File: RecipeListTableViewController.h - bagian NSPredicate dan cache FRC

#import <UIKit/UIKit.h>
#import "RecipeAddViewController.h"

@interface RecipeListTableViewController : UITableViewController <RecipeAddDelegate, NSFetchedResultsControllerDelegate>

@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) NSManagedObject *type;

Berkas: RecipeListTableViewController.m

#import "RecipeListTableViewController.h"
#import "RecipeDetailViewController.h"
#import "Recipe.h"
#import "RecipeTableViewCell.h"
#import "Recipe+Extensions.h"
#import "TypeSelectionViewController.h"
#import "IngredientDetailViewController.h"
#import "Ingredient.h"
#import "WhereViewController.h"
#import "FavoriteListTableViewController.h"
#import "RecipeTypeTableViewController.h"
#import "RecipeType.h"


@interface RecipeListTableViewController () <NSFetchedResultsControllerDelegate, UISearchBarDelegate, UISearchResultsUpdating>

@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, strong) NSArray *filteredList;
@property (nonatomic, strong) NSFetchRequest *searchFetchRequest;
@property (nonatomic, strong) UISearchController *searchController;

typedef NS_ENUM(NSInteger, RecipesSearchScope)
{
searchScopeRecipe = 0,
searchScopeIngredients = 1
};


@end

@implementation RecipeListTableViewController


#pragma mark - Fetched results controller

- (NSFetchedResultsController *)fetchedResultsController {

// Set up the fetched results controller if needed.
if (_fetchedResultsController == nil) {
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Recipe" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

[NSFetchedResultsController deleteCacheWithName:@"Recipe"];

    // Create predicate
    //if (self.type) {
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"type == %@", self.type];
    [fetchRequest setPredicate:predicate];
    //}


    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

    [fetchRequest setSortDescriptors:sortDescriptors];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Recipe"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error])
    {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    }
}

return _fetchedResultsController;
}

/

Ketika saya mengatur cache FRC ke "Resep". Itu crash. Ini menunjukkan petunjuk ini untuk melihat cache CoreData: KESALAHAN FATAL: Cache persisten dari informasi bagian tidak cocok dengan konfigurasi saat ini. Anda telah secara ilegal memutasi permintaan pengambilan NSFetchedResultsController, predikatnya, atau deskripsi pengurutannya...

Jika saya menyetel cache ke nil, atau menambahkan [NSFetchedResultsController deleteCacheWithName:@"Recipe"]; sebelum predikat ditetapkan, semuanya berjalan sesuai harapan. Saya memiliki cache ini di pengontrol tampilan awal dan pengontrol tampilan kedua. Mungkin itu masalahnya - saya hanya memerlukan cache di pengontrol tampilan awal?


person Chuck    schedule 27.08.2016    source sumber


Jawaban (1)


Pertama, menurut saya model data Anda perlu sedikit penyempurnaan. Setiap RecipeType mungkin dapat memiliki banyak Recipes yang terkait. Jadi hubungan dari RecipeType ke Recipe seharusnya ke-banyak. Jika Anda mengubahnya di editor model data, dan membuat ulang kelas model, Anda akan memiliki kelas RecipeType yang terlihat seperti ini:

@class Recipe;

@interface RecipeType : NSManagedObject
// not sure what purpose this property serves; it might now be superfluous...
@property (nonatomic, strong) NSManagedObject *type;

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSSet<Recipe *> *recipes;

@end 

Saya berasumsi untuk saat ini bahwa setiap Recipe hanya dapat dimiliki oleh satu RecipeType. Jadi hubungan kebalikannya, dari Recipe ke RecipeType harus ke-satu, dan kelas Recipe akan memiliki properti:

*property (nonatomic, strong) RecipeType *type;

Selanjutnya, Anda ingin RecipeListTableViewController Anda hanya menampilkan Recipes yang terkait dengan RecipeType yang relevan. Untuk mencapainya, Anda perlu menambahkan predikat ke pengontrol hasil yang diambil. Dalam metode fetchedResultsController, tambahkan:

if (self.recipeType) {
    fetchRequest.predicate = [NSPredicate predicateWithFormat:@"type == %@", self.recipeType];
}

(Anda juga perlu mengubah pencarian Anda untuk membatasi pencarian pada RecipeType yang relevan). Di RecipeTypeTableViewContoller, prepareForSegue Anda hanya perlu melewati RecipeType yang benar:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {    
    if ([[segue identifier] isEqualToString:@"showRecipes"]) {
        NSLog(@"Setting RecipeType for the RecipeListTableViewController");
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        RecipeType *selectedType = [self.fetchedResultsController objectAtIndexPath:indexPath];
        RecipeListTableViewController *recipeListViewController = segue.destinationViewController;
        recipeListViewController.recipeType = selectedType;
        recipeListViewController.managedObjectContext = self.managedObjectContext;
    }
}

Setiap kali Anda menambahkan Recipe baru, Anda harus menetapkannya ke RecipeType yang benar. Jadi di RecipeListViewController ubah prepareForSegue Anda untuk mengatur hubungan:

...
else if ([segue.identifier isEqualToString:kAddRecipeSegueID]) {
    // add a recipe
    //
    Recipe *newRecipe = [NSEntityDescription insertNewObjectForEntityForName:@"Recipe" inManagedObjectContext:self.managedObjectContext];
    newRecipe.type = self.recipeType;

    UINavigationController *navController = segue.destinationViewController;
    RecipeAddViewController *addController = (RecipeAddViewController *)navController.topViewController;
    addController.delegate = self;  // do didAddRecipe delegate method is called when cancel or save are tapped
    addController.recipe = newRecipe;
}
person pbasdf    schedule 28.08.2016
comment
Jawaban Anda mendapat nilai A untuk akurasi. Pencarian kode teratas. Terima kasih.... Berhasil. Tapi kemudian tidak dan saya menerima ini bukan karena Anda benar/tidak. - person Chuck; 29.08.2016
comment
Saya mengkonfigurasi ulang RecipeType. Menghapus subkelas dan menggunakan tipe NSManagedObject *yang ada dari Kelas Resep. Saya mendapatkan daftar jenis resep saya dan ketika saya memilih Snack, itu menunjukkan 2 resep makanan ringan. Luar biasa. - person Chuck; 29.08.2016
comment
Tapi kemudian ketika saya kembali ke daftar kategori dan memilih tipe lain, itu crash. Saya memulai ulang sim aplikasi dan memilih jenis lain dan melewati daftar yang benar. Tapi saya pilih tipe yang tidak ada resepnya muncul meja kosong lalu kalau saya kembali pilih tipe lain, malah ada beberapa resep malah mejanya kosong. Maaf untuk banyak komentar - kembali dengan senang hati. - person Chuck; 29.08.2016
comment
[kode] @interface Resep : NSManagedObject [kode]@property (nonatomik, kuat) NSManagedObject *type; [code]@end [code]// Buat predikat if (self.type) {fetchRequest.predicate = [NSPredicate predicateWithFormat:@type == %@, self.type]; //[fetchRequest setPredicate:predikat]; }[kode] - person Chuck; 29.08.2016
comment
[kode]- (void)prepareForSegue adalah 100% Terima kasih jika ([[pengidentifikasi segue] isEqualToString:@showRecipes]) { NSLog(@Setting RecipeType untuk RecipeListTableViewController); NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; Resep *selectedType = [self.fetchedResultsController objectAtIndexPath:indexPath]; RecipeListTableViewController *recipeListViewController = segue.destinationViewController; resepListViewController.type = tipe yang dipilih; resepListViewController.managedObjectContext = self.managedObjectContext;[kode] - person Chuck; 29.08.2016
comment
@Chuck Tidak yakin saya memahami komentar Anda. Sudahkah Anda menyelesaikan masalahnya? Beri tahu saya jika ada sesuatu yang luar biasa. - person pbasdf; 29.08.2016
comment
Maaf ya, saya tahu saya menjadi gila dengan komentar. Jawaban Anda tentang segue dan predikatnya terlihat akurat. Terima kasih - Setelah dikonfigurasi ulang, Kelas Resep memiliki tipe NSManaged Object *yang saya gunakan dan menghilangkan semua referensi ke subkelas RecipeType. Konfigurasi baru menunjukkan daftar jenis dan ketika saya memilih salah satu, itu menunjukkan jenis resep yang benar. Tetapi ketika saya kembali ke daftar jenis dan memilih jenis lain, itu macet. Saya dapat memulai ulang simulator dan memilih jenis lain dan kembali dengan benar. - person Chuck; 30.08.2016
comment
Tetapi jika saya memilih tipe yang tidak memiliki resep maka akan memberikan tabel kosong seperti yang diharapkan dan jika saya kembali ke daftar tipe dan memilih tipe lain maka semua tipe lainnya akan dikembalikan sebagai kosong. Jadi sepertinya berhasil tetapi hanya satu kali. Mungkin tabel jenis resep perlu diatur ulang pada saat kembali? Ada saran Terima kasih lagi. - person Chuck; 30.08.2016
comment
Tidak yakin di mana harus meletakkan @property (nonatomic, strong) NSSet <Recipe *> *recipes; sekarang. Saya memilikinya di RecipeTypeTVC.h Juga @class Recipe di sini. Dan @dynamic di RecipeTypeTVC.m. Dan tidak yakin di mana ini bisa digunakan? - person Chuck; 30.08.2016
comment
segmen persiapan mendapatkan tipenya sekarang Recipe *selectedType = [self.fetchedResultsController objectAtIndexPath:indexPath]; RecipeListTableViewController *recipeListViewController = segue.destinationViewController; recipeListViewController.type = selectedType; recipeListViewController.managedObjectContext = self.managedObjectContext; - person Chuck; 30.08.2016
comment
Oke setel NS Cache saya ke nil - sekarang berfungsi seperti pesona `NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest ManagedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];' - person Chuck; 30.08.2016
comment
jadi selanjutnya mengarah ke cara menyimpan cache dan mengimplementasikan deleteCacheWithName ? - person Chuck; 30.08.2016
comment
@Chuck Definisi properti recipes harus dalam .h untuk subkelas untuk entitas Type - tetapi jika Anda tidak menggunakan subkelas, definisi ini tidak diperlukan. Anda harus memastikan bahwa hubungan antara Type dan Recipe diatur dengan benar sebagai ke-banyak. Tidak yakin mengapa cache FRC mempengaruhi banyak hal; dapatkah Anda menunjukkan kesalahan dari kerusakan tersebut? Selain itu, lebih baik mengedit pertanyaan Anda dan menambahkan kode/kesalahan di sana daripada menambahkan komentar. - person pbasdf; 30.08.2016
comment
Wow - Terima kasih telah memberikan saran baik untuk poster kedua kalinya. Saya sangat takut untuk memposting karena takut seseorang akan tertawa dan menyuruh saya mempelajari dox Apple. Kamu sangat baik. Saya akan mengerjakan ulang kesalahan tersebut dan segera mempostingnya dan akan menampilkan editan kode dalam pertanyaan saya, sesuai saran Anda. Hanya satu poin lain di sini. Apakah saya memerlukan cache FRC untuk berada di kedua kelas tampilan tabel dengan tipe dan resep? Atau apakah saya hanya perlu mereferensikan cache di tabel pertama? Dan, Apakah saya memerlukan cache sama sekali? - person Chuck; 31.08.2016
comment
@Chuck Cache FRC menyimpan detail objek mana yang berada di bagian mana - jadi Anda tidak boleh menggunakan nama cache yang sama untuk FRC terpisah (kecuali jika FRC tersebut menampilkan persis informasi yang sama). Dalam kasus Anda, keduanya menampilkan informasi yang sangat berbeda, jadi jika Anda ingin keduanya menggunakan cache, gunakan nama cache yang berbeda. Tapi cache tidak diperlukan. Mereka mempercepat jika Anda memiliki sejumlah besar objek, tapi saya ragu mereka akan membuat perbedaan yang berarti dalam kasus Anda. - person pbasdf; 31.08.2016