【问题标题】:How to display unarchived custom NSView objects如何显示未归档的自定义 NSView 对象
【发布时间】:2010-10-29 03:45:36
【问题描述】:

我正在学习 Cocoa 编程,但我不知道如何 归档和取消归档自定义 NSView 子类

我制作了一个显示窗口的玩具应用程序。这个窗口 包含我的自定义 BackgroundView 类的实例(存档于 xib 文件)。单击此 BackgroundView 中的任意位置会创建并 显示一个以点击点为原点的蓝色方块。这个广场是 我的 Square 类的一个实例。所有这些都按我的预期工作。

Square 类实现了 NSCoding 协议。我已经添加 dataOfType: typeName: error: 和 readfromData: ofType: error: 方法 到 MyDocument 类。据我从日志语句中可以看出, 方块被归档到文件中,当文件被取消归档时 已加载。但我无法让方块显示在 窗户。 Square 类的 drawWithRect: 方法永远不会被调用, 即使我在每个方格上都调用了 setNeedsDisplay:YES。

代码如下:

Square.h
#import <Cocoa/Cocoa.h>
@interface Square : NSView <NSCoding> {
}
@end

Square.m
#import "Square.h"
@implementation Square

- (id)initWithFrame:(NSRect)frame {
   self = [super initWithFrame:frame];
   return self;
}

- (void)drawRect:(NSRect)rect {
       [[NSColor blueColor] set];
       NSBezierPath *newPath = [NSBezierPath bezierPathWithRect:[self bounds]];
       [newPath fill];
}

-(void)encodeWithCoder:(NSCoder *)coder
{
       [coder encodeRect:[self frame] forKey:@"frame"];
}

-(id)initWithCoder:(NSCoder *)coder
{
       NSRect theRect = [coder decodeRectForKey:@"frame"];
       self = [super initWithFrame:theRect];
       return self;
}
@end
-----
BackgroundView.h
#import <Cocoa/Cocoa.h>
@interface BackgroundView : NSView {
}
@end

BackgroundView.m
#import "BackgroundView.h"
#import "Square.h"
@implementation BackgroundView

- (id)initWithFrame:(NSRect)frame {
   self = [super initWithFrame:frame];
   if (self) {
       // Initialization code here.
   }
   return self;
}

- (void)drawRect:(NSRect)rect {
       for (Square *subview in self.subviews)
               [subview setNeedsDisplay:YES];
}

-(void)mouseDown:(NSEvent *)theEvent {
       NSPoint unsetClick = [theEvent locationInWindow];
       NSPoint theClick = [self convertPoint:unsetClick fromView:nil];
       NSRect theRect;
       theRect.origin = theClick;
       theRect.size.width = 100.00;
       theRect.size.height = 100.00;
       Square *newSquare = [[Square alloc] initWithFrame:theRect];
       [self addSubview:newSquare];
       [newSquare setNeedsDisplay:YES];
}
@end
------
MyDocument.h
#import <Cocoa/Cocoa.h>
@class BackgroundView;

@interface MyDocument : NSDocument
{
       IBOutlet BackgroundView *theBackgroundView;
}
@end

MyDocument.m
#import "MyDocument.h"

@implementation MyDocument

- (id)init
{
   self = [super init];
   return self;
}

- (NSString *)windowNibName
{
   return @"MyDocument";
}

- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
   [super windowControllerDidLoadNib:aController];
}

- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
{
   return [NSKeyedArchiver
archivedDataWithRootObject:[theBackgroundView subviews]];
   if ( outError != NULL ) {
               *outError = [NSError errorWithDomain:NSOSStatusErrorDomain
code:unimpErr userInfo:NULL];
       }
       return nil;
}

- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName
error:(NSError **)outError
{
   [theBackgroundView setSubviews:[NSKeyedUnarchiver
unarchiveObjectWithData:data]];
   [theBackgroundView setNeedsDisplay:YES];
   if ( outError != NULL ) {
               *outError = [NSError errorWithDomain:NSOSStatusErrorDomain
code:unimpErr userInfo:NULL];
       }
   return YES;
}

@end

【问题讨论】:

    标签: cocoa nsview


    【解决方案1】:

    由于 Square 是 NSView 的子类,而 NSView 也实现了 NSCoding,所以需要调用 super 对 encodeWithCoder: 和 initWithCoder: 的实现。

    @implementation Square
    - (id)initWithFrame:(NSRect)frame
    {
        return [super initWithFrame:frame];
    }
    
    -(id)initWithCoder:(NSCoder *)coder
    {
        if ((self = [super initWithCoder:coder]))
        {
            NSRect theRect = [coder decodeRectForKey:@"frame"];
            self = [super initWithFrame:theRect];
            return self;
        }
    }
    
    - (void)encodeWithCoder:(NSCoder *)coder
    {
        [super encodeWithCoder:coder];
        [coder encodeRect:[self frame] forKey:@"frame"];
    }
    
    - (void)drawRect:(NSRect)rect
    {
        [[NSColor blueColor] set];
        [[NSBezierPath bezierPathWithRect:[self bounds]] fill];
    }
    @end
    

    【讨论】:

      【解决方案2】:

      正如我所见,您没有添加任何 initWithXXX 和 encodeWithXXX 方法,因为您没有自定义成员变量。

      我建议查看 Apple 的 Sketch Example

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-11
        • 1970-01-01
        • 1970-01-01
        • 2021-10-15
        • 2012-05-10
        相关资源
        最近更新 更多