重新加载tableview根据通知删除对象后在coredata显示奇怪的结果 [英] reloading tableview as per notification after deletion of object in coredata shows weird result

查看:90
本文介绍了重新加载tableview根据通知删除对象后在coredata显示奇怪的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是这个coredata的新用户。只是为了熟悉关系我创建了两个实体CategoryList(包括属性'类')和ExpenseList(包括属性'amountspent'),它有一个很多关系。从'CategoryList'到'ExpenseList'的关系是'expenselist'。
第一个表格显示每个类别的总费用,如

 食物-150 
交通-100
mobile -100
shopping -500

,第二个表格显示个别费用

  food -100 
food -50
transportation -100
mobile -50
mobile -50
购物-200
购物-100
购物-200

我写了代码从我的第二个tableview删除一个单独的费用行使用对象id,因为它的线程安全。当我从我的第二个表视图删除食物条目说

  food -50 



当我回到第一个tableview时,应该更新食物并显示

  food -100 

我已使用默认通知中心和第一个表视图每当对象被删除时发送通知(由nslog检查)。当第一个tableview接收到一个通知,它重新加载tableview中的数据。但是,当重新加载tableview对于其对象从下一个tableview中删除的类别显示不受欢迎的值。
两个表视图都由导航控制器连接。



这是我的第一个表格的m.file。

  #importdisplayTable.h
#importCategoryList.h
#importExpenseList.h
#importIncomeList.h
#importcoreAppDelegate.h
@interface displayTable()

@end

@implementation displayTable
- (NSManagedObjectContext *)managedObjectContext
{
NSManagedObjectContext * context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if([delegate performSelector:@selector(managedObjectContext)]){
context = [delegate managedObjectContext];
}
return context;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if(self){
//自定义初始化
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
todaysL = [[todayslist alloc] init];
self.expenseArray = [[NSMutableArray alloc]
initWithObjects:@0.00,
@0.00,
@0.00,
@0.00 ,
@0.00,
@0.00,
nil];
self.categoryArray = [[NSMutableArray alloc]
initWithObjects:@food,
@transportation,
@fuel,
@mobile ,
@shopping,
@others,
nil];
[self populateExpenses];
NSOperationQueue * mainQueue = [NSOperationQueue mainQueue];
[NSNotificationCenter defaultCenter]
addObserverForName:NSManagedObjectContextObjectsDidChangeNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * notification)
{
NSLog(@Notification received!);
[self populateExpenses];
// [self viewDidLoad];
[self.tableView reloadData];
}];
//取消注释以下行以保留演示文稿之间的选择。
// self.clearsSelectionOnViewWillAppear = NO;
//取消注释以下行以在此视图控制器的导航栏中显示编辑按钮。

// self.navigationItem.rightBarButtonItem = self.editButtonItem;

}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
//处理可以重新创建的任何资源。
}

#pragma mark - 表视图数据源

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
/ /#warning可能不完全的方法实现。
//返回节的数量。
return 1;

}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//#warning不完全方法实现。
//返回节中的行数。
return [self.categoryArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * CellIdentifier = @Cell
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//配置单元格...

if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [_categoryArray objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [_expenseArray objectAtIndex:indexPath.row];
return cell;
}

这是我提取数据的函数 p>

   - (void)populateExpenses 
{

NSManagedObjectContext * managedObjectContexts = [self managedObjectContext];
NSEntityDescription * categorylistEntity = [NSEntityDescription entityForName:@CategoryListinManagedObjectContext:managedObjectContext];
NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:categorylistEntity];
NSError * error = nil;
NSArray * fetchedObjects = [managedObjectContext executeFetchRequest:request error:& error];
if(fetchedObjects == nil)
{
NSLog(@your fetching cause error);
}
else
{
for(CategoryList * categoryL in fetchedObjects)
{
if([categoryL.categories isEqualToString:@food])
{
(categoryL.expenselist中的ExpenseList * expenseL)
{
food = food + expenseL.amountSpent;
// NSLog(@display food%f,food);
}
NSString * foodString = [NSString stringWithFormat:@%。2f,food];
[self.expenseArray replaceObjectAtIndex:0 withObject:foodString];
// NSLog(@foooood%f,food);
}
else if([categoryL.categories isEqualToString:@transportation])
{
for(ExpenseList * expenseL in categoryL.expenselist)
{
transportation = transportation + expenseL.amountSpent;
}
NSString * transportationString = [NSString stringWithFormat:@%。2f,transportation];
[self.expenseArray replaceObjectAtIndex:1 withObject:transportationString];
}
else if([categoryL.categories isEqualToString:@fuel])
{
for(ExpenseList * expenseL in categoryL.expenselist)
{
fuel = fuel + expenseL.amountSpent;
}
NSString * fuelString = [NSString stringWithFormat:@%。2f,fuel];
[self.expenseArray replaceObjectAtIndex:2 withObject:fuelString];
}
else if([categoryL.categories isEqualToString:@mobile])
{
for(ExpenseList * expenseL in categoryL.expenselist)
{
mobile = mobile + expenseL.amountSpent;
}
NSString * mobileString = [NSString stringWithFormat:@%。2f,mobile];
[self.expenseArray replaceObjectAtIndex:3 withObject:mobileString];
}
else if([categoryL.categories isEqualToString:@shopping])
{
for(ExpenseList * expenseL in categoryL.expenselist)
{
shopping = shopping + expenseL.amountSpent;
}
NSString * shoppingString = [NSString stringWithFormat:@%。2f,shopping];
[self.expenseArray replaceObjectAtIndex:4 withObject:shoppingString];
}
else if([categoryL.categories isEqualToString:@others])
for(ExpenseList * expenseL in categoryL.expenselist)
{
others = others + expenseL.amountSpent;
}
NSString * othersString = [NSString stringWithFormat:@%。2f,others];
[self.expenseArray replaceObjectAtIndex:5 withObject:othersString];
NSLog(@%@,othersString);
}
// NSLog(@count%d,self.expenseArray.count);
}
}
/ *

//覆盖以支持表视图的条件编辑。

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
//如果不想要指定的项目是可编辑的。
return YES;
}
* /

/ *
//覆盖以支持编辑表视图。
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(editingStyle == UITableViewCellEditingStyleDelete){
/ /删除数据源中的行
[tableView deleteRowsAtIndexPaths:@ [indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if(editingStyle == UITableViewCellEditingStyleInsert){
//创建一个相应类的新实例,将其插入数组,并向表视图中添加一个新行
}
}
* /

/ *
//覆盖以支持重新排列表视图。
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}

* b
$ b / *

//覆盖以支持表视图的条件重排。

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
//返回NO,可订购。
return YES;
}

* /

#pragma mark - 表视图委托
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath * )indexPath
{
//导航逻辑可以在这里。创建并推送另一个视图控制器。
/ *
<#DetailViewController#> * detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@< #Nib name#> bundle:nil];

// ...

//将所选对象传递给新的视图控制器。

[self.navigationController pushViewController:detailViewController animated:YES];

* /
}
@end

但是当我退出并重新启动我的应用程序一切都更新,因为它应该是,但不是在删除后立即更新。我不明白为什么。另外我不知道这是否是正确的方式做核心数据的事情。如果有人可以指导我,请提前感谢

解决方案

是的,您缺少核心数据的一些核心概念,



您拥有数据库中顶级类别的名称,但您不知道什么顺序你将得到他们,所以你创建一个单独的数组,并做一堆复杂的东西,以相同的顺序从数据库中获取值。



完全移除你的categoryArray属性,并在你的populateExpenses函数中移除你的categoryArray属性。 ,只是做fetch(带一个排序子句)。将fetchedObjects保存到数组属性。



你需要做一个抓取来获取你的顶级对象,但一旦你有它们,很少



CategoryList * category = [_fetchedObjects objecatAtIndex:indexPath 。行];
cell.textLabel.text = category.categories;
cell.detailTextLabel.text = [[category valueForKeyPath:@expenselist。@ sum.amountSpent] description];



您不需要预先 -



更新对象以确保您的更改被注意到: -

  for(NSManagedObject * object in self.categoryArray){
[self.managedObjectContext refreshObject:object mergeChanges:YES];
}

这大多数时候是告诉对象它需要下次请求时重新更新其值。



希望这有助于。


I am new to this coredata. Just to be familiar with relationship i created two entities CategoryList (consists of attribute 'categories') and ExpenseList(consists of attribute 'amountspent') which has a to many relationship. Relationship from 'CategoryList' To 'ExpenseList' is 'expenselist'. The 1st tableview shows the total expense in each categories like

food              -150  
transportation    -100  
mobile            -100  
shopping          -500    

and the second tableview shows individual expenses like

food              -100  
food              -50  
transportation    -100  
mobile            -50  
mobile            -50  
shopping          -200  
shopping          -100  
shopping          -200  

I have written the codes to delete an individual expense row from my second tableview using object id since its threadsafe. When i delete a food entry from my second table view say

food              -50

and when i navigate back to 1st tableview it should update food and show

food               -100

I have registered the first tableview with default notification center and first table view is sending notification (checked by nslog) whenever an object is deleted. When first tableview receives a notification it reloads the data in the tableview. But while reloading the tableview is showing undesired value for the category whose object is deleted from the next tableview. Both tableviews are connected by navigation controller.

Here is my m.file for the 1st tableview.

#import "displayTable.h"
#import "CategoryList.h"
#import "ExpenseList.h"
#import "IncomeList.h"
#import "coreAppDelegate.h"
@interface displayTable ()

@end

@implementation displayTable
- (NSManagedObjectContext *)managedObjectContext
{
    NSManagedObjectContext *context = nil;
    id delegate = [[UIApplication sharedApplication] delegate];
    if ([delegate performSelector:@selector(managedObjectContext)]) {
        context = [delegate managedObjectContext];
    }
    return context;
}
- (id)initWithStyle:(UITableViewStyle)style
{
   self = [super initWithStyle:style];
   if (self) {
    // Custom initialization
   }
   return self;
}
- (void)viewDidLoad
{
   [super viewDidLoad];
   todaysL = [[todayslist alloc]init];
   self.expenseArray = [[NSMutableArray alloc] 
                       initWithObjects:@"0.00",
                                       @"0.00",
                                       @"0.00",
                                       @"0.00",
                                       @"0.00",
                                       @"0.00", 
                                       nil];
  self.categoryArray = [[NSMutableArray alloc] 
                    initWithObjects:@"food",
                                    @"transportation",
                                    @"fuel",
                                    @"mobile",
                                    @"shopping", 
                                    @"others", 
                                    nil];
  [self populateExpenses];  
  NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];   
  [[NSNotificationCenter defaultCenter]          
      addObserverForName:NSManagedObjectContextObjectsDidChangeNotification 
                  object:nil 
                   queue:[NSOperationQueue mainQueue] 
              usingBlock:^(NSNotification *notification)
              {
                  NSLog(@"Notification received!");
                  [self populateExpenses];
                  //   [self viewDidLoad];
                  [self.tableView reloadData];
              }];
// 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;

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

#pragma mark-Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
   //#warning Potentially incomplete method implementation.
   // Return the number of sections.
   return 1;

}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
   //#warning Incomplete method implementation.
   // Return the number of rows in the section.
   return [self.categoryArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   static NSString *CellIdentifier = @"Cell";
   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
  // Configure the cell...

   if(cell == nil)
   {
       cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
                                     reuseIdentifier:CellIdentifier];
   }
   cell.textLabel.text = [_categoryArray objectAtIndex:indexPath.row];
   cell.detailTextLabel.text = [_expenseArray objectAtIndex:indexPath.row];
   return cell;
}

this is my function for fetching data

-(void)populateExpenses
{

    NSManagedObjectContext *managedObjectContexts = [self managedObjectContext];
    NSEntityDescription *categorylistEntity = [NSEntityDescription entityForName:@"CategoryList" inManagedObjectContext:managedObjectContext];
    NSFetchRequest *request = [[NSFetchRequest alloc]init];
    [request setEntity:categorylistEntity];
    NSError *error =nil;
    NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:request error:&error];
    if(fetchedObjects == nil)
    {
        NSLog(@"your fetching cause error");
    }
    else
    {
        for(CategoryList *categoryL in fetchedObjects)
        {
            if([categoryL.categories isEqualToString: @"food"] )
            {
                for(ExpenseList *expenseL in categoryL.expenselist)
                {
                    food = food + expenseL.amountSpent;
                    //NSLog(@"display food %f",food);                       
                }
                NSString *foodString = [NSString stringWithFormat:@"%.2f",food];
                [self.expenseArray replaceObjectAtIndex:0 withObject:foodString];
                //NSLog(@"foooood%f",food);
            }
            else if ([categoryL.categories isEqualToString: @"transportation"])
            {
                for(ExpenseList *expenseL in categoryL.expenselist)
                {
                    transportation = transportation + expenseL.amountSpent;
                }
                NSString *transportationString = [NSString stringWithFormat:@"%.2f",transportation];
                [self.expenseArray replaceObjectAtIndex:1 withObject:transportationString];
            }
            else if ([categoryL.categories isEqualToString: @"fuel"])
            {
                for(ExpenseList *expenseL in categoryL.expenselist)
                {
                    fuel = fuel + expenseL.amountSpent;
                }
                NSString *fuelString = [NSString stringWithFormat:@"%.2f",fuel];
                [self.expenseArray replaceObjectAtIndex:2 withObject:fuelString];
            }
            else if([categoryL.categories isEqualToString: @"mobile"])
            {
                for(ExpenseList *expenseL in categoryL.expenselist)
                {
                    mobile = mobile + expenseL.amountSpent;
                }
                NSString *mobileString = [NSString stringWithFormat:@"%.2f",mobile];
                [self.expenseArray replaceObjectAtIndex:3 withObject:mobileString];
            }
            else if([categoryL.categories isEqualToString: @"shopping"])
            {
                for(ExpenseList *expenseL in categoryL.expenselist)
                {
                    shopping = shopping + expenseL.amountSpent;
                }
                NSString *shoppingString = [NSString stringWithFormat:@"%.2f",shopping];
                [self.expenseArray replaceObjectAtIndex:4 withObject:shoppingString];
            }
            else if ([categoryL.categories isEqualToString:@"others"])
                for(ExpenseList *expenseL in categoryL.expenselist)
                {
                    others = others + expenseL.amountSpent;
                }
                NSString *othersString = [NSString stringWithFormat:@"%.2f",others];
                [self.expenseArray replaceObjectAtIndex:5 withObject:othersString];
            NSLog(@"%@",othersString);
            }
        //NSLog(@"count %d", self.expenseArray.count);
    }
 }
 /*

// Override to support conditional editing of the table view.

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/

/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
    // Delete the row from the data source
    [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}   
else if (editingStyle == UITableViewCellEditingStyleInsert) {
    // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}   
}
*/

 /*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}

*/

/*

// Override to support conditional rearranging of the table view.

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
    return YES;
}

*/

#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
 <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];

 // ...

 // Pass the selected object to the new view controller.

 [self.navigationController pushViewController:detailViewController animated:YES];

 */
}
@end

but when i quit and restart my app everything is updated as it is supposed to be, but not updating immediately after deleting. I could not figure it why. Also i don't know whether this is the right way of doing things with coredata. If anyone could guide me, Thanks in advance

解决方案

Yes, you're missing some of the core concepts of core data, which means you're doing a lot more work than you need to.

You have the names of the top level categories in the database, but you don't know what order you're going to get them in, so you create a separate array and do a bunch of complex stuff to get the values from the database in the same order. Much better to just add a 'displayOrder' field to the database and add an order by field to the fetch.

Get rid of your categoryArray property completely and in your populateExpenses function, just do the fetch ( with a sort clause). Save the fetchedObjects to an array property.

You need to do a fetch to get your top level objects in the first place, but once you have them, it is rare that you need to do more fetches.

In your cellForRowAtIndexPath:

CategoryList* category = [_fetchedObjects objecatAtIndex:indexPath.row]; cell.textLabel.text = category.categories; cell.detailTextLabel.text = [[category valueForKeyPath:@"expenselist.@sum.amountSpent"] description];

You don't need to pre-fetch this, you can do this at the time you display the data.

Updating the objects to ensure your changes are taken notice of :-

for ( NSManagedObject* object in self.categoryArray) {
    [self.managedObjectContext refreshObject: object mergeChanges:YES];
}

What this does, most of the time, is tell the object that it needs to re-update it's values next time they are requested.

Hope this helps.

这篇关于重新加载tableview根据通知删除对象后在coredata显示奇怪的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆