如何更改此代码以使其不违反MVC原则?

时间:2012-06-13 06:40:56

标签: objective-c ios model-view-controller uiviewcontroller

我正在制作化学反应的测验应用程序。该应用程序向用户提供问题,用户在两个单独的文本字段中键入反应物和产品。

我有一个数据类,其中包含所有可能的测验问题。然后,根据特定参数,数据类从可能的问题池中选择一定数量的问题,并将它们混合成一个数组quizQuestions

我还有一个视图控制器quizController。对于每个问题,都会加载quizController的新实例。 vc需要数据来知道要显示哪个问题,正确答案是什么等等。

这是我在数据和vc之间进行通信的原始解决方案。

我创建了一个数据类实例data。 我为第一个问题创建了vc1,并将data设置为vc1的属性,并将其标记设置为1,以便从数据中加载第一个问题。

在用户回答第一个问题后,我使用vc2的方法创建了一个新的视图控制器vc1,使标记比最后一个vc更多,以便加载第二个问题,并将datavc1的属性传递给vc2

然后我重复其他问题。

然而,这不是很好的设计,我正在寻找更好的解决方案。我不认为我可以使用类方法,因为data应该包含一组随机问题。下面我有数据类的代码。

// the data class as it is now, designed for instance methods

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

    //Questions of the same type belong to a "ROW" (Reaction of Week)
    //individual questions
    // Items in array: (1)Question, (2)Reactants, (3)Products, (4)Elements for keyboard

    NSArray *R1Q1 = [[NSArray alloc] initWithObjects:@"Methanol is burned completely in air", @"2CH₃OH(l) + 3O₂(g)", @"2CO₂(g) + 4H₂O", @"C,H,O", nil];
    NSArray *R1Q2 = [[NSArray alloc] initWithObjects:@"Ammonia is burned in excess oxygen gas", @"4NH₃(g) + 7H₂O(l)", @"4NO₂(g) + 6H₂O(l)", @"N,H,O", nil];
    NSArray *R1Q3 = [[NSArray alloc] initWithObjects:@"Hydrogen sulfide gas is burned in excess oxygen gas", @"2H₂S(g) + 3O₂(g)", @"CO₂(g) + 2SO₂(g)", @"H,S,O", nil];

    NSArray *R2Q1 = [[NSArray alloc] initWithObjects:@"Solid potassium is added to a flask of oxygen gas", @"K(s) + O₂(g)", @"KO₂(s)", @"K,O", nil];
    NSArray *R2Q2 = [[NSArray alloc] initWithObjects:@"Sodium metal is dropped into a flask of pure water", @"2Na(s) + H₂O(l)", @"2Na⁺(aq) + 2OH⁻(aq) + H₂(g)", @"Na,H,O", nil];
    NSArray *R2Q3 = [[NSArray alloc] initWithObjects:@"A piece of lithium is heated strongly in oxygen", @"4Li(s) + O₂(g)", @"2Li₂O(s)", @"Li,O", nil];

    NSArray *R3Q1 = [[NSArray alloc] initWithObjects:@"Solutions of potassium chloride and silver nitrate are mixed", @"Ag⁺(aq) + Cl⁻(aq)", @"AgCl(s)", @"K,Cl,Ag,N,O", nil];
    NSArray *R3Q2 = [[NSArray alloc] initWithObjects:@"Solutions of iron(III) nitrate and sodium hydroxide are mixed", @"Fe³⁺(aq) + 3OH⁻(aq)", @"Fe(OH)₃(s)", @"Fe,N,O,Na,H", nil];
    NSArray *R3Q3 = [[NSArray alloc] initWithObjects:@"Solutions of nickel iodide and barium hydroxide are mixed", @"Ni²⁺(aq) + 2OH⁻(aq)", @"Ni(OH)₂(s)", @"Ni,I,Ba,OH", nil];
    // add rest

    //organize questions into groups
    row1 = [[NSArray alloc] initWithObjects:R1Q1, R1Q2, R1Q3, nil];
    row2 = [[NSArray alloc] initWithObjects:R2Q1, R2Q2, R2Q3, nil];
    row3 = [[NSArray alloc] initWithObjects:R3Q1, R3Q2, R3Q3, nil];
    //add rest

    // array containing all questions
    allRows = [[NSMutableArray alloc] initWithObjects:row1, row2, row3, nil];

    //in a real situation, needs to be given to class dynamically 
    self.maxRowNumber = 3;
    self.questionsPerRow = 2;
}

return self;
}

- (void)selectQuestions {

self.quizQuestions = [[NSMutableArray alloc] init];

for (int j = 0; j<self.maxRowNumber; j++) {
   //shuffle each row
    NSMutableArray *row = [NSMutableArray arrayWithArray:[allRows objectAtIndex:j]];
    [row shuffle];

    //add questions from each row
    for (int k = 0; k<self.questionsPerRow; k++)       
       [quizQuestions addObject:[row objectAtIndex:k]];

}

[quizQuestions shuffle];

}

查看控制器代码摘录

    # pragma mark Cell Setup
    //1st cell in tableview
    - (void) setUpEquationCell: (UITableView *) tableView  {

    equationCell = (EquationCell *) [tableView dequeueReusableCellWithIdentifier:@"equationCell"];

    if (equationCell == nil) {   
        NSArray *nib =   [[NSBundle mainBundle] loadNibNamed:@"EquationCell" owner:self options:nil];
        equationCell = (EquationCell*) [nib objectAtIndex:0];
        [equationCell.leftButton addTarget:self action:@selector(addDissociateCell) forControlEvents:UIControlEventTouchUpInside];
        [equationCell.rightButton addTarget:self action:@selector(addBalanceCell) forControlEvents:UIControlEventTouchUpInside];
    }

}

    - (void) setUpBalanceCell: (UITableView *) tableView  {
            //2nd cell in tableview

    balanceCell = (BalanceCell *) [tableView dequeueReusableCellWithIdentifier:@"balanceCell"];

    if (balanceCell == nil) {   
        NSArray *nib =   [[NSBundle mainBundle] loadNibNamed:@"BalanceCell" owner:self options:nil];
        balanceCell = (BalanceCell*) [nib objectAtIndex:0];

        // stores data from equation cell into model
        for (FormulaLabel *label in equationCell.leftView.equationOrder) 
            [leftData.equation addObject:label.text];                                                 

        for (FormulaLabel *label in equationCell.rightView.equationOrder)  
            [rightData.equation addObject:label.text];

        [leftData setUpBalancedEquation];
        [rightData setUpBalancedEquation];
        [self setUpView:balanceCell.leftView fromArray:leftData.equation toArray:leftBalanceItems];
        [self setUpView:balanceCell.rightView fromArray:rightData.equation toArray:rightBalanceItems];
        [self addBalanceTapMethodInArray:leftBalanceItems Data:leftData];
        [self addBalanceTapMethodInArray:rightBalanceItems Data:rightData];
    }

}
    - (void) setUpDissociateCell: (UITableView *) tableView  {
    dissCell = (DissociateCell *) [tableView dequeueReusableCellWithIdentifier:@"dissCell"];

    if (dissCell == nil) {   
        NSArray *nib =   [[NSBundle mainBundle] loadNibNamed:@"DissociateCell" owner:self options:nil];
        dissCell = (DissociateCell*) [nib objectAtIndex:0];

        leftData.disEquation = [[NSMutableArray alloc] init];
        rightData.disEquation = [[NSMutableArray alloc] init];

        // stores data from equation cell into model
        for (FormulaLabel *label in equationCell.leftView.equationOrder) 
            [leftData.disEquation addObject:label.text];                                                 

        for (FormulaLabel *label in equationCell.rightView.equationOrder)  
            [rightData.disEquation addObject:label.text];

        [self setUpView:dissCell.leftView fromArray:leftData.disEquation toArray:leftDisItems];
        [self setUpView:dissCell.rightView fromArray:rightData.disEquation toArray:rightDisItems];
        [self addDissTapToArray:leftDisItems fromData:leftData inView:dissCell.leftView];
        [self addDissTapToArray:rightDisItems fromData:rightData inView:dissCell.rightView];
        [dissCell.dissociateButton addTarget:self action:@selector(dissociate) forControlEvents:UIControlEventTouchUpInside];
        }
    [dissCell.rightButton addTarget:self action:@selector(addBalanceCell) forControlEvents:UIControlEventTouchUpInside];

}




    - (void)addDissociateCell {

    [cellOrder addObject:@"dissociateCell"];
    [table reloadData];
    NSIndexPath *myIndexPath = [NSIndexPath indexPathForRow:0 inSection:([cellOrder count]-1)];
    [table scrollToRowAtIndexPath:myIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}


- (void) addDissTapToArray:(NSMutableArray*)viewOrder fromData:(EquationData*)data inView:(UIView*)view {

    NSString *leftOrRight;

    if (view == dissCell.leftView) 
        leftOrRight = @"left";    
    else 
        leftOrRight = @"right";

    for (int j=0; j < [viewOrder count]; j++) {


        if (j%2==0) {
            UIView *formulaView = [viewOrder objectAtIndex:j];
            //dissociate method
            FalseTarget *target = [[FalseTarget alloc] initWithVC:self leftOrRightView:leftOrRight];
            UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:target action:@selector(dissTap:)]; 
            [formulaView addGestureRecognizer:tap];

            // cancelling method
            FalseTarget *target2 = [[FalseTarget alloc] initWithVC:self Data:data ViewList:viewOrder view:view];
            UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:target2 action:@selector(dissLongTap:)];
            [formulaView addGestureRecognizer:longPress];
                  }

    }
}
- (void)addCompoundToLabel:(UIGestureRecognizer *)recognizer leftOrRight:(NSString*)leftRight{
    if( [recognizer state] == UIGestureRecognizerStateEnded ) {
        FormulaLabel* label = (FormulaLabel*)[recognizer view];  
        dissIndex = label.tag;
        dissCell.unDissociated.text = label.text;
        currentDissCellView = leftRight;
    }
}

- (void)dissociate {

    EquationData *data;
    NSMutableArray *viewOrder;
    UIView *view;

    if ([currentDissCellView isEqualToString:@"left"]) {
        data = leftData;
        viewOrder = leftDisItems;
        view = dissCell.leftView;
    }

    else {
        data = rightData;
        viewOrder = rightDisItems;
        view = dissCell.rightView;
    }

    FormulaLabel *c1 = [dissCell.leftTextField.equationOrder objectAtIndex:0];
    FormulaLabel *c2 = [dissCell.rightTextField.equationOrder objectAtIndex:0];
    [data updateDisEquationAtIndex:dissIndex withCompound1:c1.text Compound2:c2.text];

    for (UIView *view in viewOrder) 
        [view removeFromSuperview];

    [viewOrder removeAllObjects];
    [self setUpView:view fromArray:data.disEquation toArray:viewOrder];
    [self addDissTapToArray:viewOrder fromData:data inView:view];

}

- (void) cancelIons:(id)sender fromData:(EquationData *)data inView:(UIView *)view withViewList:(NSMutableArray *)viewlist {
    if( [sender state] == UIGestureRecognizerStateEnded ) {

        FormulaLabel* label = (FormulaLabel*)[sender view];  
        int index = label.tag;
        [data.disEquation removeObjectAtIndex:index];

        for (UIView *formulaView in viewlist) 
            [formulaView removeFromSuperview];

        [viewlist removeAllObjects];
        [self setUpView:view fromArray:data.disEquation toArray:viewlist];
        [self addDissTapToArray:viewlist fromData:data inView:view];


    }
}

    - (void)addBalanceCell {

    [cellOrder addObject:@"balanceCell"];
    [table reloadData];
    NSIndexPath *myIndexPath = [NSIndexPath indexPathForRow:0 inSection:([cellOrder count]-1)];
    [table scrollToRowAtIndexPath:myIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];

    leftBalanceItems = [[NSMutableArray alloc] init];
    rightBalanceItems = [[NSMutableArray alloc] init];
}

    - (void) addBalanceTapMethodInArray:(NSMutableArray *)balanceItems Data:(EquationData *)data {

    FalseTarget *target = [[FalseTarget alloc] initWithVC:self Data:data ViewList:balanceItems view:nil];

    for (UIView *view in balanceItems) {
        UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:target action:@selector(tap:)];
        [view addGestureRecognizer:tap];
    }

}


    - (void)updateBalanceLabelofSender:(UIGestureRecognizer*)sender fromData:(EquationData *)data inArray:(NSMutableArray *)balanceItems {

    FormulaLabel* label = (FormulaLabel*)[sender view];
    int oldWidth = label.frame.size.width;
    label.text = [data updateBalancedatIndex:label.tag];
    [label sizeToFit];
    int newWidth = label.frame.size.width;
    int difference = newWidth - oldWidth;
    int labelIndex = label.tag * 2;

    for (int j = 0; j<[balanceItems count]; j++) {
        // adjusts coordinate of  all views to the right of tapped item

        if (j > labelIndex){
            UIView *item = [balanceItems objectAtIndex:j];
            item.frame = CGRectMake(item.frame.origin.x + difference, item.frame.origin.y, item.frame.size.width, item.frame.size.height);
        }
    }
}


    - (void)setUpView:(UIView *)view fromArray:(NSMutableArray *)equationData toArray:(NSMutableArray *)balanceItems {

    int labelCount = 0; //label #
    int startingPoint = 5; //x vaiue where first label starts

    for (NSString *equationText in equationData) {

        //add text
        FormulaLabel *tempLabel = [[FormulaLabel alloc] initWithFrame:CGRectMake(startingPoint, 2, 10, 22)];
        tempLabel.text = equationText;
        [tempLabel sizeToFit];
        [view addSubview:tempLabel];
        tempLabel.tag = labelCount;
        [balanceItems addObject:tempLabel];
        //set location of '+'
        startingPoint = tempLabel.frame.origin.x + tempLabel.frame.size.width + 3;

        if (labelCount != [equationData count]-1) { //not the last label

            UILabel *plus = [[[UILabel alloc] initWithFrame:CGRectMake(startingPoint, 5, 10, 10)]autorelease];
            plus.text = @"+";
            plus.font = [UIFont systemFontOfSize:13];
            [plus sizeToFit];
            [view addSubview:plus];
            startingPoint = plus.frame.origin.x + plus.frame.size.width + 3;
            [balanceItems addObject:plus];
        }

        labelCount ++;
        [tempLabel release];
    }

}

3 个答案:

答案 0 :(得分:0)

我不会这样做,因为你强迫UIViewController知道数据模型(同时使它成为它的属性)。我会做的是一个类,使用类方法(而不是对象方法)将创建数据源。您仍然需要以某种方式保留UIViewController中的数据,但我认为NSArrayNSDictionary足够好:

-(void)viewDidLoad{
  [superViewDidLoad];
  myArray = [MyModel createDataSourceForTag:myTag];
} 

答案 1 :(得分:0)

我想你应该选择模型结构。

<强> 1。模型:模型代表实体。在你的情况下,我可以创建两个实体Round,Question

@interface Round: NSObject {

    NSUInteger *roundId; // 1, 2 = if it is required to check then this mi
    NSArray *questions; // Array that contains objects for Question entity
}


@interface Question:NSObject {

    NSString *questionText;
    NSString *options1Text;
    NSString *options2Text;
    NSString *options3Text;
}


@interface DataManager:NSObject {

    NSArray *rounds; // Array that contains object for Round entity
}

+(void)sharedInstance;

<强> 2。 DataManger :DataManager将管理您的实体对象。此数据管理器将是sharedInstance类。因此,在初始化管理器时,将创建实体并插入数据。

第3。 ViewController:现在在视图控制器中,您可以直接使用sharedInstace,如下所示:

[[DataManager sharedInstance] rounds]

您可以轻松获取用于创建sharedInstance类的代码。

现在,您可以在整个应用程序的任何位置使用此轮次。 所以它很容易访问。例如,如果您需要第1轮第2个问题第3个选项,那么以相同的方式编写代码

第1轮

Round *r = [[[DataManager sharedInstance] rounds] objectAtIndex:0];

问题2

Question *q = [[r questions] objectAtIndex:1];

问题文本和选项3

NSLog(@"questionText : %@  3rd Option: %@", q.questionText, q.option3Text)

享受编码:)

答案 2 :(得分:0)

为什么不能将一个带有question-property的视图控制器类用于重载属性的setter方法以将UI更新为新数据:

在QuestionViewController.h文件中

@property (retain, nonatomic) Question* myQuestionData;
在QuestionViewController.m中

-(void) setMyQuestionData:(Question*)newData {
   [myQuestionData autorelease];
   myQuestionData = [newData retain];
   [self updateUIElements];
}