MVC基本问题

时间:2014-05-26 18:34:24

标签: objective-c cocoa model-view-controller

我遇到了MVC主要概念的问题。我认为我知道应该链接和发生什么,但我有一个基本的MVC问题。

"项目"

用户在视图(MVCView.h/m)上绘制形状的基本应用程序。当他拖动鼠标时,将在视图上绘制形状。但我还希望在MVCViewController.h/m NSMutableArray* shapeArray中添加形状。然后,ViewController将使用MVCModel

中的规范调用形状为init的MVCView

问题

我不知道如何调用这些函数(参见下面的代码和/或项目),因为"他们"总是说你永远不能直接从视图中调用模型类。因为这是我以前的做法。 (视图类中有NSMutableArray

所以,请帮助我。我喜欢理解语法/概念!

在此处下载项目:(谷歌驱动器) MVC Controller Project

代码: MVCViewController.h:

#import <Cocoa/Cocoa.h>
#import "MVCModel.h"


@interface MVCViewController : NSViewController
{
    //Array to save the shapes to
    NSMutableArray* shapeArray;
}

-(void)addShapeWithBeginPoint:(NSPoint)beginPoint andEndPoint:(NSPoint)endPoint withColor:(NSColor*)fillColor;

-(NSInteger)countItemsInArray;

@end

MVCViewController.m:

 #import "MVCViewController.h"

@interface MVCViewController ()

@end

@implementation MVCViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        //Create array when view is loaded.
        shapeArray = [[NSMutableArray alloc]init];
    }
    return self;
}

-(void)addShapeWithBeginPoint:(NSPoint)beginPoint andEndPoint:(NSPoint)endPoint withColor:(NSColor*)fillColor
{
    //Add the model to the MVCViewController Array!
    MVCModel *shape = [[MVCModel alloc]initWithName:[NSString stringWithFormat:@"Shape: %d",(int)[self countItemsInArray]] atBeginPoint:beginPoint endAt:endPoint fillWithColor:fillColor];
    [shapeArray addObject:shape];


    //In the Future
    //In the near future some other shapes like circles, lines, arrows etc have to be added using tags from a PopUpButton.
    //Also the color has to be set to the NSColorPicker Color.
    //In the Future
}


-(NSInteger)countItemsInArray{
    //Count the amount of items in array
    NSLog(@"%d",(int)shapeArray.count);

    return [shapeArray count];
}

    @end

MVCModel.h:

  #import <Foundation/Foundation.h>

@interface MVCModel : NSObject
{
    NSString* name;
    NSPoint beginPoint;
    NSPoint endPoint;
    NSColor* fillColor;
}

-(id)initWithName:(NSString*)name atBeginPoint:(NSPoint)beginPoint endAt:(NSPoint)endPoint fillWithColor:(NSColor*)fillColor;


@end

MVCModel.m:

    #import "MVCModel.h"

@implementation MVCModel



//Every shape has these variables.

-(id)initWithName:(NSString*)newName atBeginPoint:(NSPoint)newBeginPoint endAt:(NSPoint)newEndPoint fillWithColor:(NSColor*)newFillColor{
    self = [super init];
    if(self)
    {
        name = newName;
        beginPoint = newBeginPoint;
        endPoint = newEndPoint;
        fillColor = newFillColor;
    }
    return self;
}
@end

MVCView.h:

#import <Cocoa/Cocoa.h>

@interface MVCView : NSView{
    NSPoint cursorStartPoint;
    NSPoint cursorEndPoint;
    NSSize size;
}

@end

MVCView.m:

#import "MVCView.h"

@implementation MVCView

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

- (void)drawRect:(NSRect)dirtyRect
{
    [super drawRect:dirtyRect];

    //drawing the shape when the user clicks.
    [[NSColor gridColor]set];
    NSBezierPath *path = [NSBezierPath bezierPathWithRect:NSMakeRect(cursorStartPoint.x,
                                                                     cursorStartPoint.y,
                                                                     size.width,
                                                                     size.height)];
    [path stroke];



    //drawing all the Shapes to the view
    // So the code I think of should be:

    /*

     for(MVCModel* shape in shape.array)
     {
     NSBezierPath* path = [NSBezierPath bezierPathWithRect:[NSMakeRect(shape.beginPoint.x,shape.beginPoint.y,shape.endPoint.x, shape.endPoint.y)]]
     }


     BUT as MVC states, the view can never "talk" to the data model which it does here. So Do I make an instance of it? 
     How will it work?

     */

}

-(void)mouseDown:(NSEvent *)theEvent
{
    //Get the clicked value from the cursor in the view
    NSLog(@"Mouse Clicked");
    cursorStartPoint = [self convertPoint:[theEvent locationInWindow]fromView:nil];

}

-(void)mouseDragged:(NSEvent *)theEvent
{
    //get the last cursorvalue from the cursor in the view
    //Set needs display to draw something so the user can see it.
    NSLog(@"Mouse Dragged");
    cursorEndPoint = [self convertPoint:[theEvent locationInWindow]fromView:nil];
    size.width = cursorEndPoint.x - cursorStartPoint.x;
    size.height = cursorEndPoint.y - cursorStartPoint.y;

    [self setNeedsDisplay:YES];

}

-(void)mouseUp:(NSEvent *)theEvent
{
    /*Call MVCViewController to call:
    -(void)addShapeWithBeginPoint:(NSPoint)beginPoint andEndPoint:(NSPoint)endPoint withColor:(NSColor*)fillColor

    So the data model to init itself and send itself back to the controller to add itself to the shapeArray in MVCViewController
    To eventually call the DrawRect: Method in MVCView(self) to draw itself with the function:
     [self SetNeedsDisplay:YES];

     */
}

@end

1 个答案:

答案 0 :(得分:0)

“他们”说你不应该直接从视图中调用模型类。 但话虽如此,当我们需要视图让模型知道事件已经发生并且需要更新模型数据时,这是一个常见问题。

为此,您创建一个名为NSNotifications的无线电广播,并且viewController调整到事件的广播中。在此广播中,您发送事件的元数据,然后对数据库中收到的数据执行操作。 基本上,我们从不调用从视图中改变模型的方法,我们只是调入视图中的事件,让控制器调用方法。您还可以设置特定视图或控制器的委托以代表其执行操作(即更新模型)。

一些参考资料 - https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/nsnotificationcenter_Class/Reference/Reference.html

http://nshipster.com/nsnotification-and-nsnotificationcenter/

对不起,我没有给出你问题的具体答案,但这是我用来处理查看事件和更新模型的一般方法。