不能执行授权

时间:2014-12-23 17:42:57

标签: ios objective-c core-data nsfetchedresultscontroller

我有一个表视图控制器和一个视图控制器。

  • StackTableViewController - 字符串列表

  • HomeViewController - 带有标签的空视图控制器

HomeViewController标签应始终显示StackTableViewController的第一个sting。

我需要确保删除第一个字符串以显示新的第一个字符串。

这就是我遇到问题的地方......如果我删除了第一个字符串并返回到HomeViewController,标签仍然是我刚刚删除的字符串....如果我终止应用并再次打开它,标签中显示的正确字符串。

到目前为止我是这样做的:

这是我的StackTableViewController.h + .m中的相关方法:

@protocol StackTableViewControllerDelegate <NSObject>

@optional

-(void)didDeleteObject;

@end

@interface StackTableViewController : UITableViewController <UITableViewDataSource,UITableViewDelegate> 

@property (strong,nonatomic) id<StackTableViewControllerDelegate> delegate;
@property (strong, nonatomic) NSString *currentTarget;

@end



#import "StackTableViewController.h"
#import "Target.h"
#import "StackTableViewCell.h"
#import "HomeViewController.h"
#import "CoreDataStack.h"

@interface StackTableViewController () <NSFetchedResultsControllerDelegate>

@property (nonatomic, strong) NSFetchedResultsController *fetchedResultController;

@end

@implementation StackTableViewController

- (id)init {

    self = [super initWithNibName:@"StackTableViewController" bundle:nil];
    if (self) {
        // Do something
        [self.fetchedResultController performFetch:nil];
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
        Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
        self.currentTarget = current.body;
    }
    return self;
}

- (void)viewDidLoad {

    [super viewDidLoad];
    self.navigationItem.rightBarButtonItem = self.editButtonItem;
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
    Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
    self.currentTarget = current.body;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];
    CoreDataStack *stack = [CoreDataStack defaultStack];
    [[stack managedObjectContext] deleteObject:target];
    [stack saveContext];

    if ([_delegate respondsToSelector:@selector(didDeleteObject)]) {
        [_delegate didDeleteObject];
    }

}

这是HomeViewController.h + .m:

中的相关方法
#import <UIKit/UIKit.h>
#import "StackTableViewController.h"

@interface HomeViewController : UIViewController {

    StackTableViewController *stackTableViewController;
}

@property (strong, nonatomic) IBOutlet UILabel *homeLabel;

- (IBAction)goToStack:(id)sender;



#import "StackTableViewController.h"

@interface HomeViewController () <StackTableViewControllerDelegate>


@end

@implementation HomeViewController

- (id)init {
    self = [super initWithNibName:@"HomeViewController" bundle:nil];
    if (self) {
        // Do something
        stackTableViewController = [[StackTableViewController alloc] init];
        stackTableViewController.delegate = self;
    }
    return self;
}

- (void)viewDidLoad {

    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    [self.navigationController setNavigationBarHidden:YES];
    self.homeLabel.font = [UIFont fontWithName:@"Candara-Bold" size:40];

    self.homeLabel.text = stackTableViewController.currentTarget;
}

- (void)didDeleteObject {
    self.homeLabel.text = stackTableViewController.currentTarget;
}

- (IBAction)goToStack:(id)sender {
    StackTableViewController *vc = [[StackTableViewController alloc] init];
    [self.navigationController pushViewController:vc animated:YES];
}

CoreDataStack.h + .m:

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@interface CoreDataStack : NSObject

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

+ (instancetype)defaultStack;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;


@end


#import "CoreDataStack.h"

@implementation CoreDataStack

#pragma mark - Core Data stack

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

+ (instancetype)defaultStack {

    static CoreDataStack *defaultStack;
    static dispatch_once_t onceTocken;
    dispatch_once (&onceTocken, ^{
        defaultStack = [[self alloc] init];
    });

    return defaultStack;
}


- (NSURL *)applicationDocumentsDirectory {
    // The directory the application uses to store the Core Data store file. This code uses a directory named "digitalCrown.Treats" in the application's documents directory.
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

- (NSManagedObjectModel *)managedObjectModel {
    // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Treats" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    // Create the coordinator and store

    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Treats.sqlite"];
    NSError *error = nil;
    NSString *failureReason = @"There was an error creating or loading the application's saved data.";
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        // Report any error we got.
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
        dict[NSLocalizedFailureReasonErrorKey] = failureReason;
        dict[NSUnderlyingErrorKey] = error;
        error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _persistentStoreCoordinator;
}


- (NSManagedObjectContext *)managedObjectContext {
    // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (!coordinator) {
        return nil;
    }
    _managedObjectContext = [[NSManagedObjectContext alloc] init];
    [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    return _managedObjectContext;
}

#pragma mark - Core Data Saving support

- (void)saveContext {
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        NSError *error = nil;
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
            // Replace this implementation with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }
}


@end

请帮助我解决这个问题,我正在尝试各种各样的方式,但可能我错过了与视图控制器生命周期有关的东西。

(CoreDataStack是单身人士)

TNX !!

5 个答案:

答案 0 :(得分:1)

我注意到你没有透露你在哪里以及如何返回,如你所说:

  

这就是我遇到问题的地方......如果我删除了第一个字符串   并且回到HomeViewController ,标签仍然是   我刚删除的字符串

您有两种选择来解决它:

1)使用viewWillAppear功能并更新其中的所需文字。

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    // get the most recent updates and assign to the UI
    self.homeLabel.text = stackTableViewController.currentTarget;
}

因此,您刚刚加载此UI或从下一个UI返回,这将有助于获取最新更新。

2)在致电popViewControllerAnimated之前,请确保您已更新文字。

if (_delegate && [_delegate respondsToSelector:@selector(didDeleteObject)]) 
{
     // updated the UI through delegate
    [_delegate didDeleteObject];
}
 // This should be call when your work is done, since
 // It will start ending the session of this UI so it will obviously 
 // miss the track of the `_delegate` variable.
[self.navigationController popViewControllerAnimated:YES];

希望它有所帮助!

答案 1 :(得分:0)

我认为您只需在删除对象后重置currentTarget属性:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];
    CoreDataStack *stack = [CoreDataStack defaultStack];
    [[stack managedObjectContext] deleteObject:target];
    [stack saveContext];
    // The FRC should recognise that the deletion has happened, and consequently have updated its
    // indexes, so the following will access the NEW first item, even if it has just changed:
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
    Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
    self.currentTarget = current.body;

    if ([_delegate respondsToSelector:@selector(didDeleteObject)]) {
        [_delegate didDeleteObject];
    }
}

答案 2 :(得分:0)

我认为您最好以不同的方式设置变量。具体来说,似乎你最好有一个单独的对象来保存和管理堆栈,但这是一种方法来完成你设置的。我已经编写了一个基本的应用程序,其中包含了代码中的所有UI。以下是相关文件:

//  AppDelegate.h
//  StackTableTesting
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

//  AppDelegate.m
//  StackTableTesting
#import "AppDelegate.h"
#import "HomeViewController.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    HomeViewController *vc          = [[HomeViewController alloc] init];
    UINavigationController *nav     = [[UINavigationController alloc] initWithRootViewController:vc];
    nav.navigationBar.translucent   = NO;
    self.window                     = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController  = nav;
    [self.window makeKeyAndVisible];
    return YES;
}
@end

//  Created by Michael McEvoy on 12/23/14.
//  Copyright (c) 2014 Mustard Seed Software LLC. All rights reserved.
#import <UIKit/UIKit.h>
#import "StackTableViewController.h"
@interface HomeViewController : UIViewController
@end

//  HomeViewController.m
//  StackTableTesting
#import "HomeViewController.h"
#import "StackTableViewController.h"
@interface HomeViewController () <StackTableViewControllerDelegate> {

}
#pragma mark - 
#pragma mark - Private Properties
@property (strong, nonatomic) StackTableViewController  *stackTableViewController;
@property (strong, nonatomic) UILabel                   *homeLabel;
@end
#pragma mark - 
#pragma mark - Implementation
@implementation HomeViewController
#pragma mark - 
#pragma mark - Initialization
- (instancetype)init {
    self = [super init];
    if (self != nil) {
        self.stackTableViewController           = [[StackTableViewController alloc] init];
        self.stackTableViewController.delegate  = self;
    }
    return self;
}
#pragma mark - 
#pragma mark - View Lifecycle
- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupUserInterface];
}
#pragma mark - 
#pragma mark - StackTableViewControllerDelegate Protocol Methods
- (void)didDeleteObject {
    self.homeLabel.text = self.stackTableViewController.currentTarget;
}
#pragma mark - 
#pragma mark - Button Presses
- (void)goToStack {
    [self.navigationController pushViewController:self.stackTableViewController animated:YES];
}
#pragma mark - 
#pragma mark - UI Setup
// This is because there's no Storyboard
- (void)setupUserInterface {
    self.homeLabel              = [[UILabel alloc] init];
    self.homeLabel.font         = [UIFont fontWithName:@"Candara-Bold" size:40];
    self.homeLabel.frame        = CGRectMake(20, 20, 200, 50);
    self.homeLabel.text         = self.stackTableViewController.currentTarget;
    self.homeLabel.textColor    = [UIColor blackColor];
    [self.view addSubview:self.homeLabel];
    UIButton *button            = [UIButton buttonWithType:UIButtonTypeSystem];
    button.frame                = CGRectMake(20, 80, 200, 50);
    [button addTarget:self action:@selector(goToStack) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"Go To Stack" forState:UIControlStateNormal];
    [self.view addSubview:button];
    self.view.backgroundColor   = [UIColor whiteColor];
}
@end

//  StackTableViewController.h
//  StackTableTesting
#import <UIKit/UIKit.h>
@protocol StackTableViewControllerDelegate <NSObject>
- (void)didDeleteObject;
@end
@interface StackTableViewController : UITableViewController {

}
#pragma mark - 
#pragma mark - Properties
@property (weak, nonatomic) id <StackTableViewControllerDelegate> delegate;
@property (copy, nonatomic) NSString *currentTarget;
@end

//  StackTableViewController.m
//  StackTableTesting
#import "StackTableViewController.h"
@interface StackTableViewController () {

}
#pragma mark -
#pragma mark - Private Properties
@property (strong, nonatomic) NSMutableArray *stack;
@end
#pragma mark - 
#pragma mark - Implementation
@implementation StackTableViewController
#pragma mark - 
#pragma mark - Initialization
- (instancetype)init {
    self = [super init];
    if (self != nil) {
        self.stack = [NSMutableArray array];
        for (int i = 0; i < 10; i = i + 1) {
            [self.stack addObject:[NSString stringWithFormat:@"Item %d", i + 1]];
            self.currentTarget = self.stack[0];
        }
    }
    return self;
}
#pragma mark -
#pragma mark - View Lifecycle
- (void)viewDidLoad {
    [super viewDidLoad];
    self.navigationItem.rightBarButtonItem  = self.editButtonItem;
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
}
#pragma mark - 
#pragma mark - UITableViewDataSource Protocol Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.stack.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell   = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
    cell.textLabel.text     = self.stack[indexPath.row];
    return cell;
}
#pragma mark - 
#pragma mark - UITableViewDelegate Protocol Methods
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    [self.stack removeObjectAtIndex:indexPath.row];
    [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    self.currentTarget = self.stack[0];
    if ([_delegate respondsToSelector:@selector(didDeleteObject)]) {
        [_delegate didDeleteObject];
    }
}
@end

我认为此设置会根据您的问题执行您尝试执行的操作。

答案 3 :(得分:0)

再次出现HomeViewController时,再次设置标签值。这应该工作,因为你说重新启动应用程序。解决了这个问题。这也应该有用。

- (void)viewWillAppear:(BOOL)animated {
    self.homeLabel.text = stackTableViewController.currentTarget;
}

答案 4 :(得分:0)

- (id)init {
    self = [super initWithNibName:@"HomeViewController" bundle:nil];
    if (self) {
        // Do something
        stackTableViewController = [[StackTableViewController alloc] init];
        stackTableViewController.delegate = self;
    }
    return self;
}

在此,您创建StackTableViewController并将self设置为委托。这很好。

- (IBAction)goToStack:(id)sender {
    StackTableViewController *vc = [[StackTableViewController alloc] init];
    [self.navigationController pushViewController:vc animated:YES];
}

在这里,您创建一个全新的 StackTableViewController并推送它,而无需设置委托对象。您在推送的视图控制器中所做的任何更改都不会反馈到主视图控制器,因为未设置委托。

推送现有的stackViewController,或在新创建的代理上设置代理。

另外一点,这是:

@property (strong,nonatomic) id<StackTableViewControllerDelegate> delegate;

加上这个:

@interface HomeViewController : UIViewController {

    StackTableViewController *stackTableViewController;
}

您将堆栈表视图控制器的委托设置为主视图控制器(拥有堆栈表视图控制器)这一事实意味着您正在创建一个强大的引用循环。代表通常会weak为此目的提供参考。