从表视图中删除行时出现异常。 iOS 目标-C

Posted

技术标签:

【中文标题】从表视图中删除行时出现异常。 iOS 目标-C【英文标题】:Exception while deleting row from table view. iOS Objective-C 【发布时间】:2014-06-17 09:46:40 【问题描述】:

我正在尝试从表视图中删除一行。我有一个包含要显示的对象的数组(文章)。我按照教程中的说明做所有事情。我删除行,然后删除相应的对象形式数组,但总是得到执行。我已经尝试过类似情况的解决方案,但他们无法解决问题。我已经被这个问题困住了第 3 天。希望大家能帮忙。谢谢你。我将根据需要添加任何其他信息或代码。

编辑:我可能已经找到了问题的原因。我在每次登录时从外部服务器导入新文章。每次登录时,我都会发送最后添加文章的日期,作为回应,我会收到所有不在我的数据库中的文章。您将在代码中看到它。我猜 self.article 仅在完成行删除后才使用接收到的数据进行更新。我可能是错的(很可能:))。希望这会有所帮助。

InboxViewController.m

    //
//  ArticleViewController.m
//  ReadLater
//
//  Created by Ibragim Gapuraev on 09/06/2014.
//  Copyright (c) 2014 Sermilion. All rights reserved.
//

#import "InboxViewController.h"
#import "LoginViewController.h"

@interface InboxViewController ()

@end

@implementation InboxViewController

@synthesize db,articles, response, jsonData;


- (NSMutableArray* ) articles

    if (!articles) 
        articles = [[NSMutableArray alloc] initWithCapacity:20];
    

    return articles;


- (Database* ) db

    if (!db) 
        db = [[Database alloc] init];
    
    return db;



- (void)setInboxList:(NSMutableArray* )inboxList

    self.articles = inboxList;


//---------------------------------Getting data from web-------------------------------------------//

/**
 The method will connect to a given url and send date of article that has been added at last.
 Then, connectionDidFinishLoading will receive json array of all articles, that have been added to server database after that time
 **/
- (void) viewWillAppear:(BOOL)animated

    [super viewWillAppear:animated];

    NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost/nextril/index.php"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];

    NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

    [self.db openDatabase];
    NSString* date_added = [self.db getLastArticleDate];
    [self.db closeDatabase];

    //send id of article that was added last, to server,
    //which will return json arrya of all articles with id greater then the one sent
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:[date_added dataUsingEncoding:NSUTF8StringEncoding]];

    if (connection) 
        NSLog(@"viewWillAppear: Connecting to server to get data...");
    else
        NSLog(@"viewWillAppear: Error while connecting...");
    




- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data

    response = [[NSData alloc] initWithData:data];


//Check if data been received
- (void) connectionDidFinishLoading:(NSURLConnection *)connection

    if(sizeof(response)>0)
        //NSLog(@"Got response from server %@", response);
        NSError* error;
        NSArray* json = [NSJSONSerialization
                              JSONObjectWithData:response //1
                              options:kNilOptions
                              error:&error];

        self.jsonData = [[NSMutableArray alloc] initWithArray:json];
        int count = 0;
        [self.db openDatabase];

        for (int i=0; i<self.jsonData.count; i++) 

            NSDictionary *item = [self.jsonData objectAtIndex:i];
            NSInteger article_id = [[item objectForKey:@"article_id"]integerValue];
            NSString* content = [item objectForKey:@"content"];
            NSString* author = [item objectForKey:@"author"];
            NSString* date = [item objectForKey:@"date"];

            NSString* url = [item objectForKey:@"url"];
            NSString* tags = [item objectForKey:@"tags"];
            NSInteger archived = [[item objectForKey:@"archived"]integerValue];
            NSString* title = [item objectForKey:@"title"];
            //NSLog(@"",);
            Article* article = [[Article alloc]initWithId:article_id content:content author:author date:date url:url tags:tags arhived:archived title:title];

            BOOL added = [self.db addArticleToLocalDatabase:article];
            BOOL addedToUser = [self.db addArticleToInbox:article];
            [self.articles addObject:article];
            count++;
            if (added == true && addedToUser == true) 
                NSLog(@"connectionDidFinishLoading: Articles has been imported. Size: %d %@", self.articles.count, self.articles);
            else
                NSLog(@"connectionDidFinishLoading: Failed to import article.");
            
        
        [self.db closeDatabase];
    else
        NSLog(@"connectionDidFinishLoading: Did not get resopnse from server: %@", response);
    
    connection = nil;

//----------------------------------------------------------------------------------------------------



- (void)viewDidLoad

    [super viewDidLoad];
    [self.db openDatabase];
    self.articles = [self.db importAllInboxArticles:16];
    [self.db closeDatabase];

    self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:self.navigationItem.rightBarButtonItem,self.editButtonItem, nil];


    //NSLog(@"Number of articles in inboxArticles %d", articles.count);
    // Do any additional setup after loading the view.


#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

    // Return the number of sections.
    return 1;


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    // Return the number of rows in the section.
    return self.articles.count;


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath




    //NSLog(@"Number of articles in articles %d", self.articles.count);
    static NSString *CellIdentifier = @"Content";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    // Configure the cell...
    Article* article = [self.articles objectAtIndex:indexPath.row];
    NSString *listingKey = article.title;
    NSString *listingValues = article.url;
    cell.textLabel.text = listingKey;
    cell.detailTextLabel.text = listingValues ;

    return cell;


// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath

    if (editingStyle == UITableViewCellEditingStyleDelete) 

        NSLog(@"Size of artilces: %d", self.articles.count);

        [tableView beginUpdates];
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [self.articles removeObjectAtIndex:indexPath.row];

        [tableView endUpdates];
        [tableView reloadRowsAtIndexPaths:(NSArray *)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
    

- (void)didReceiveMemoryWarning

    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.






@end

堆栈跟踪:

2014-06-17 11:07:49.131 稍后阅读[76572:60b] connectionDidFinishLoading:文章已导入。尺寸:4( "", "", "", "" ) 2014-06-17 11:07:51.078 ReadLater[76572:60b] 文章大小:4 2014-06-17 11:07:51.078 ReadLater[76572:60b] * -[UITableView] 中的断言失败 _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2935.137/UITableView.m:1368 2014-06-17 11:07:51.081 ReadLater[76572:60b] * 由于未捕获而终止应用程序 异常'NSInternalInconsistencyException',原因:'无效更新: 第 0 节中的行数无效。其中包含的行数 更新后的现有部分 (3) 必须等于数字 更新前该部分中包含的行数 (3),加减 从该部分插入或删除的行数(0 插入, 1 已删除)并加上或减去移入或移出的行数 该部分(0 移入,0 移出)。 * 首先抛出调用栈:( 0 CoreFoundation 0x018e61e4 exceptionPreprocess + 180 1 libobjc.A.dylib 0x016658e5 objc_exception_throw + 44 2 核心基础 0x018e6048 +[NSException raise:format:arguments:] + 136 3 基金会 0x012454de -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 116 4 UIKit 0x00313f63 -[UITableView _endCellAnimationsWithContext:] + 13402 5 UIKit 0x00323cea -[UITableView endUpdatesWithContext:] + 51 6 UIKit 0x00323d18 -[UITableView endUpdates] + 41 7 ReadLater 0x00005044 -[收件箱视图控制器 tableView:commitEditingStyle:forRowAtIndexPath:] + 484 8 UIKit 0x003356a3 -[UITableView animateDeletionOfRowWithCell:] + 107 9 UIKit 0x004be595-[UITableViewCell _swipeDeleteButtonPushed] + 70 10 libobjc.A.dylib 0x01677880 -[NSObject performSelector:withObject:withObject:] + 77 11 UIKit 0x0023d3b9 -[UIApplication sendAction:to:from:forEvent:] + 108 12 UIKit 0x0023d345 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61 13 UIKit 0x0033ebd1 -[UIControl sendAction:to:forEvent:] + 66 14 UIKit 0x0033efc6 -[UIControl _sendActionsForEvents:withEvent:] + 577 15 UIKit 0x0033e243 -[UIControl touchesEnded:withEvent:] + 641 16 UIKit 0x005d32e3 _UIGestureRecognizerUpdate + 7166 17 UIKit 0x0027ca5a -[UIWindow _sendGesturesForEvent:] + 1291 18 UIKit 0x0027d971 -[UIWindow sendEvent:] + 1021 19 UIKit 0x0024f5f2 -[UIApplication sendEvent:] + 242 20 UIKit 0x00239353 _UIApplicationHandleEventQueue + 11455 21 核心基础 0x0186f77f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 15 22 CoreFoundation 0x0186f10b __CFRunLoopDoSources0 + 235 23 CoreFoundation 0x0188c1ae __CFRunLoopRun + 910 24 CoreFoundation 0x0188b9d3 CFRunLoopRunSpecific + 467 25 核心基础 0x0188b7eb CFRunLoopRunInMode + 123 26 图形服务 0x038da5ee GSEventRunModal + 192 27 图形服务 0x038da42b GSEventRun + 104 28 UIKit 0x0023bf9b UIApplicationMain + 1225 29 ReadLater 0x0000858d 主 + 141 30 libdyld.dylib 0x01f2d701 start + 1 ) libc++abi.dylib: 以未捕获的方式终止 NSException (lldb) 类型的异常

【问题讨论】:

在重新加载tableview行之前需要更新数据源 如果您查看堆栈跟踪,您将看到您的异常发生在 InboxViewController,而不是 ArticleViewController。您应该设置一个异常断点来找到发生崩溃的地方并发布正确的代码sn -p 哦,我的错。是的,它是 InboxViewController。对此感到抱歉。 我从 NSLogs 中看到,articles 数组中最初有 4 个条目,但异常指出有 3 个。看起来还有其他东西正在从数组中删除一个元素? NSMutable 数组不是线程安全的。检索数据后,您应该使用 gcd 调度块在主线程上执行数组更新。 【参考方案1】:

我成功了!)我设置了断点并检查了发生了什么。我听取了@Paulw11 的建议,使我的 self.articles 成为不可变的,并创建了它的可变副本。然后,我决定删除重新加载视图(行)的行,一切都开始工作了。

工作代码:

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

    // Return the number of sections.
    return 1;


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    // Return the number of rows in the section.
    return safeArticles.count;


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath


    //NSLog(@"Number of articles in articles %d", self.articles.count);
    static NSString *CellIdentifier = @"Content";
    //UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    SHCTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    cell.textLabel.backgroundColor = [UIColor clearColor];

    // Configure the cell...
    Article* article = [safeArticles objectAtIndex:indexPath.row];
    NSString *listingKey = article.title;
    NSString *listingValues = article.url;
    cell.textLabel.text = listingKey;
    cell.detailTextLabel.text = listingValues ;
    cell.delegate = self;
    cell.todoItem = article;
    return cell;


//// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath

    if (editingStyle == UITableViewCellEditingStyleDelete) 

        NSLog(@"Size of artilces: %d", safeArticles.count);

        [tableView beginUpdates];
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [safeArticles removeObjectAtIndex:indexPath.row];

        [tableView endUpdates];

        ///[tableView reloadRowsAtIndexPaths:(NSArray *)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
    

【讨论】:

【参考方案2】:

只需使用以下方法重新加载这些行而不是整个表:

 - (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:   (UITableViewRowAnimation)animation

【讨论】:

我可以看到这应该在代码中,但显然这不是主要原因。我仍然得到同样的错误。我添加了堆栈跟踪。谢谢。

以上是关于从表视图中删除行时出现异常。 iOS 目标-C的主要内容,如果未能解决你的问题,请参考以下文章

从表视图中删除特定行

如何在目标c中删除表格视图中的多个部分?

单击表格视图行时出现异常

在Android Studio终端中运行时出现IO异常[重复]

从表视图中删除行

切换选项卡时删除所有子视图控制器并移至父视图控制器 IOS 目标 c