【问题标题】:NSUndoManager removeAllActionsWithTarget crashNSUndoManager removeAllActionsWithTarget 崩溃
【发布时间】:2017-01-11 23:27:30
【问题描述】:

我有一些简短的 iOS Objective-C 示例代码(从一个更大的项目中简化而来)导致 NSUndoManager 崩溃,我无法解释。

也就是说,当一个对象仅由 NSUndoManager 释放时(因为它超出了撤消级别),并且根据docs 调用removeAllActionsWithTarget:self,我得到一个 EXC_BAD_ACCESS。

// SimpleViewController.m
@interface ViewController ()
@property (nonatomic, strong) NSUndoManager *undoManager;
@end

@implementation ViewController

@synthesize undoManager;

// called from a simple button
- (IBAction)doItTapped:(id)sender
{
    CoolObject *object = [CoolObject new];
    object.undoManager = self.undoManager;
    // according to docs, object will be retained by NSUndoManager here
    // but target will not (which should be okay)
    [self.undoManager registerUndoWithTarget:self selector:@selector(notCool:) object:object];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.undoManager = [NSUndoManager new];
    self.undoManager.levelsOfUndo = 3;
}

和

// CoolObject.m
@implementation CoolObject

- (void)dealloc
{
    [self.undoManager removeAllActionsWithTarget:self];
}

@end

在第四次点击按钮 (levelsOfUndo + 1) 后,它崩溃了。 如果我用GCUndoManager 交换NSUndoManager,不会崩溃。 在 iOS 10.2 sim 和设备中测试。

感谢您的任何想法!

【问题讨论】:

    标签: ios objective-c


    【解决方案1】:

    您可能会遇到此错误,因为self.undoManager 在您使用它的那一刻没有保留。当对象已经被释放并且你尝试访问它时,你会得到错误的访问异常。

    尝试从这里更改您的代码:

    CoolObject *object = [CoolObject new];
    

    到这里:

    @interface ViewController (){
    CoolObject *object;
    }
    @property (nonatomic, strong) NSUndoManager *undoManager;
    @end
    @implementation ViewController
    - (IBAction)doItTapped:(id)sender
    {
        object = [CoolObject new];
        object.undoManager = self.undoManager;
        // according to docs, object will be retained by NSUndoManager here
        // but target will not (which should be okay)
        [self.undoManager registerUndoWithTarget:self selector:@selector(notCool:) object:object];
    }
    @end
    

    希望这会有所帮助。

    【讨论】:

    • 没有骰子,仍然崩溃。它在传递给 undoManager 的 self 上崩溃,而不是 undoManager 本身。在主代码中,UndoManager 是一个存在于整个应用程序生命周期中的单例,所以我很确定它不是 UndoManager 释放。
    【解决方案2】:

    就像我一样,您似乎误解了公认的不准确的书面文档。 docs 谈论“目标”、“对象”和“目标对象”,就好像它们实际上意味着完全相同且相同:-removeAllActionsWithTarget: 的 (id)target 参数

    换句话说,在我看来,您根本不需要在CoolObject 内部调用-removeAllActionsWithTarget:,因为CoolObject 已被指定为-registerUndoWithTarget:selector:object: 的对象,而目标是你的 ViewController。

    您可能必须在您的 NSViewController 的 -dealloc 中调用 -removeAllActionsWithTarget:,但即使在您的示例中也是不必要的,因为您的 NSViewController 拥有 NSUndoManager,因此 ViewController 不会在 undoManager 之前消失。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-02
      • 1970-01-01
      • 2011-11-22
      • 2021-05-14
      • 1970-01-01
      • 2011-07-02
      相关资源
      最近更新 更多