MVC Even在IOS的上下文中意味着什么



我曾经有一个庞大的8k+行FeedViewController,每当我想改变任何涉及状态外观的东西时,我都必须改变不少于十几个viewcontrllers,所以我决定尝试重构以遵循MVC类型标准。我将大部分功能放在 tableviewcell 中,以便我可以更改单元格类而不是 12 个文件,现在我听到"你应该保持你的 VIEWS 愚蠢......这真的有那么错吗?

//
//  TriCornerFeedCell.m
//
//
#import "NSDate+TimeAgo.h"
#import "TriCornerFeedCell.h"
#import "AFNetworking.h"

@implementation TriCornerFeedCell
-(void)refreshGestureRecognizers{
    while (self.gestureRecognizers.count) {
        [self removeGestureRecognizer:[self.gestureRecognizers objectAtIndex:0]];
    }
    UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(processDoubleTap:)];
    doubleTap.numberOfTapsRequired = 2;
    [self addGestureRecognizer:doubleTap];
    UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc]
                                          initWithTarget:self action:@selector(handleLongPress:)];
    lpgr.minimumPressDuration = 1.3; //seconds
    lpgr.delegate = self;
    [self addGestureRecognizer:lpgr];
}


-(void)refreshCell{
     _sdmanager = [SDWebImageManager sharedManager];

//Set Name Label
    self.NameLabel.text=[NSString stringWithFormat:@"%@ %@",self.statusObject.first_name,self.statusObject.last_name];
//Set Message Label
    if(self.statusObject.message!=nil){
        self.StatusLabel.enabledTextCheckingTypes = NSTextCheckingTypeLink;
        self.StatusLabel.text = self.statusObject.message;
        self.StatusLabel.delegate = self;
        [self checkForShoutoutsAndHashtags];
        self.StatusLabel.lineBreakMode=0;
        self.StatusLabel.numberOfLines=0;
        //Cell.StatusLabel.text=[tempDictionary objectForKey:@"message"];
        [self.StatusLabel sizeToFit];
    }
//Set Date Label
    NSDate *date = [[NSDate alloc] initWithTimeIntervalSince1970:self.statusObject.created];
    self.timeLabel.text=[date timeAgo];
//Set Bump Views
    if(self.statusObject.isBumped){
         [self.bumpCornerBG setBackgroundImage:[UIImage imageNamed:@"corner_bump_yellow.png"] forState:UIControlStateNormal];
    }else{
        [self.bumpCornerBG setBackgroundImage:[UIImage imageNamed:@"corner_bump_grey.png"] forState:UIControlStateNormal];
    }
    self.bumpCount.text=[@(self.statusObject.bump_count) stringValue];
    [self.bumpClearViewBtn addTarget:self action:@selector(bump:) forControlEvents:UIControlEventTouchUpInside];
    [self.bumpCornerBG addTarget:self action:@selector(bump:) forControlEvents:UIControlEventTouchUpInside];

//Set Comment Related Views

    if(self.statusObject.comment_count>0){
        NSLog(@"COMMENT_COUNT:%d",self.statusObject.comment_count);
        [self.commentCount setHidden:NO];
        [self.miniCommentColorCircle setHidden:NO];
        self.commentCount.text=[@(self.statusObject.comment_count) stringValue];
    }else{
        [self.commentCount setHidden:YES];
        [self.miniCommentColorCircle setHidden:YES];
    }
//Set Follow Btn Views
    [self.followBtn.titleLabel setFont:[UIFont fontWithName:@"BloggerSans" size:14]];
    [self.followBtn removeFromSuperview];
    if(!self.statusObject.isFollowing){
        [self.followBtn removeFromSuperview];
        UIButton *followBtn= [[UIButton alloc] initWithFrame:CGRectMake(235, 16, 75, 25)];
        [followBtn setImage:nil forState:UIControlStateNormal];
        followBtn.layer.cornerRadius =2; // this value vary as per your desire
        [followBtn.titleLabel setFont:[UIFont fontWithName:@"BloggerSans" size:14.0f]];
        followBtn.titleEdgeInsets = UIEdgeInsetsMake(3, 0, 0, 0);
        followBtn.clipsToBounds = YES;
        [followBtn setTitleColor:[self colorWithHexString:@"ff68a8"] forState:UIControlStateNormal];
        followBtn.layer.borderWidth=1.5f;
        followBtn.layer.borderColor=[[self colorWithHexString:@"ff68a8"] CGColor];
        [followBtn setTitle:@"Follow" forState:UIControlStateNormal];
        [followBtn addTarget:self action:@selector(follow) forControlEvents:UIControlEventTouchUpInside];
        self.followBtn=followBtn;
        [self addSubview:self.followBtn];
    }

//Reset icon to default in case default==nill
    [self bringSubviewToFront:self.DefaultImgBorder];
    [self bringSubviewToFront:self.DefaultImgBtn];
    UIImage *noDefault = [UIImage imageNamed:@"female_mini_no_default_icon.png"];
    [self.DefaultImgBtn setBackgroundImage:noDefault forState:UIControlStateNormal];
//Attempt to create hexagon cropped default photo
    UIImage *hex_img = [UIImage imageNamed:@"big_hex_thumb.png"];
    UIImage *tan=[UIImage imageNamed:@"feed_grey.png"];
    UIImage *finalBG= [self maskImage:tan withMask:hex_img];
    [self.DefaultImgBorder setImage:finalBG];
    NSURL *thumb_url=[NSURL URLWithString:[NSString stringWithFormat:@"%@%@",s3thumbURL,self.statusObject.thumb_img]];
    @autoreleasepool {
        [_sdmanager downloadWithURL:thumb_url
                            options:0
                           progress:^(NSInteger receivedSize, NSInteger expectedSize){}completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished){
             if (image)
             {
                 UIImage *thumbimg = image;
                 UIImage *hex_img = [UIImage imageNamed:@"big_hex_thumb.png"];
                 UIImage *noDefault = [UIImage imageNamed:@"female_mini_no_default_icon.png"];
                 [self.DefaultImgBtn setBackgroundImage:noDefault forState:UIControlStateNormal];
                 UIImage *finalImg= [self maskImage:thumbimg withMask:hex_img];
                 [self.DefaultImgBtn setBackgroundImage:finalImg forState:UIControlStateNormal ];
             }
         }];
    }
    [self.DefaultImgBtn removeTarget:nil
                              action:NULL
                    forControlEvents:UIControlEventAllEvents];
    [self.DefaultImgBtn addTarget:self action:@selector(viewProfile:) forControlEvents:UIControlEventTouchUpInside];

//Misc Stuff
    [self setSelectionStyle:UITableViewCellSelectionStyleNone];
}
#pragma mark - Interaction Methods
-(void)follow{

    [self.followSpinner removeFromSuperview];
    [self.followBtn removeFromSuperview];
    self.followSpinner = [[RTSpinKitView alloc] initWithStyle:RTSpinKitViewStyleFadingCircleAlt color: [self colorWithHexString:@"b4b4b2"] spinnerSize:25];
    [self.followSpinner setFrame:CGRectMake(260,15,30,30)];
    self.spinner.tag=9;
    [self addSubview:self.followSpinner];
    [self.statusObject follow];
}
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
    if (self.indexPath != nil && gestureRecognizer.state == UIGestureRecognizerStateBegan) {

        NSString*loggedin_uid = [[NSUserDefaults standardUserDefaults] objectForKey:@"uid"];

        if([self.statusObject.IMPORT_SOURCE isEqualToString:@"INSTAGRAM"] || [self.statusObject.IMPORT_SOURCE isEqualToString:@"TWITTER"]){
            if([loggedin_uid isEqualToString:@"1"] || [loggedin_uid isEqualToString:@"2"]){
                [self.delegate showImportAdminControls:self.indexPath];
            }
        }else{
            if([loggedin_uid isEqualToString:@"1"] || [loggedin_uid isEqualToString:@"2"]){
                [self.delegate showAdminControls:self.indexPath];
            }else if ([self.statusObject.uid isEqualToString:loggedin_uid]){
                [self.delegate deletePostAlert:self.indexPath];
            }
        }
    }
}
- (void) processDoubleTap:(UITapGestureRecognizer *)sender
{

    if (sender.state == UIGestureRecognizerStateEnded)
    {
        if (self.indexPath)
        {
            self.statusObject.indexPath=self.indexPath;
            if(!self.statusObject.isBumped){

                int value = self.statusObject.bump_count+1;
                self.statusObject.isBumped=YES;
                self.statusObject.bump_count=value;
                [self.bumpCount setText:[@(value) stringValue]];
                [self.bumpCornerBG setBackgroundImage:[UIImage imageNamed:@"corner_bump_yellow.png"] forState:UIControlStateNormal];
                UIImageView *bumpBlowUpIcon=[[UIImageView alloc]initWithFrame:CGRectMake((self.frame.size.width/2)-5, (self.frame.size.height/2)-5, 10, 10)];
                [bumpBlowUpIcon setImage:[UIImage imageNamed:@"heart_yellow.png"]];
                bumpBlowUpIcon.alpha=.2;
                [self addSubview:bumpBlowUpIcon];
                [UIView animateWithDuration:.8 delay:0 usingSpringWithDamping:.3 initialSpringVelocity:.3 options:UIViewAnimationOptionCurveEaseOut animations:^{
                    [bumpBlowUpIcon setFrame:CGRectMake((self.frame.size.width/2)-(self.frame.size.height/2), 0, self.frame.size.height, self.frame.size.height)];
                    bumpBlowUpIcon.alpha=.5;
                }completion:^(BOOL finished) {
                    [bumpBlowUpIcon removeFromSuperview];
                }];

            }else{
                int value = self.statusObject.bump_count-1;
                self.statusObject.isBumped=NO;
                self.statusObject.bump_count=value;
                [self.bumpCount setText:[@(value) stringValue]];
                [self.bumpCornerBG setBackgroundImage:[UIImage imageNamed:@"corner_bump_grey.png"] forState:UIControlStateNormal];
            }

            [self.statusObject bump];


        }
    }
}


-(void)viewProfile{

}
-(void)viewHashtag{

}

#pragma mark - Misc Methods


- (UIImage*) maskImage:(UIImage *) image withMask:(UIImage *) mask
{
    CGImageRef imageReference = image.CGImage;
    CGImageRef maskReference = mask.CGImage;
    CGImageRef imageMask = CGImageMaskCreate(CGImageGetWidth(maskReference),
                                             CGImageGetHeight(maskReference),
                                             CGImageGetBitsPerComponent(maskReference),
                                             CGImageGetBitsPerPixel(maskReference),
                                             CGImageGetBytesPerRow(maskReference),
                                             CGImageGetDataProvider(maskReference),
                                             NULL, // Decode is null
                                             YES // Should interpolate
                                             );
    CGImageRef maskedReference = CGImageCreateWithMask(imageReference, imageMask);
    CGImageRelease(imageMask);
    UIImage *maskedImage = [UIImage imageWithCGImage:maskedReference];
    CGImageRelease(maskedReference);
    return maskedImage;
}
-(UIColor*)colorWithHexString:(NSString*)hex
{
    NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
    // String should be 6 or 8 characters
    if ([cString length] < 6) return [UIColor grayColor];
    // strip 0X if it appears
    if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2];
    if ([cString length] != 6) return  [UIColor grayColor];
    // Separate into r, g, b substrings
    NSRange range;
    range.location = 0;
    range.length = 2;
    NSString *rString = [cString substringWithRange:range];
    range.location = 2;
    NSString *gString = [cString substringWithRange:range];
    range.location = 4;
    NSString *bString = [cString substringWithRange:range];
    // Scan values
    unsigned int r, g, b;
    [[NSScanner scannerWithString:rString] scanHexInt:&r];
    [[NSScanner scannerWithString:gString] scanHexInt:&g];
    [[NSScanner scannerWithString:bString] scanHexInt:&b];
    return [UIColor colorWithRed:((float) r / 255.0f)
                           green:((float) g / 255.0f)
                            blue:((float) b / 255.0f)
                           alpha:1.0f];
}
@end

好的。我试图将所有评论合并到一个合适的答案中。

当你想坚持MVC模式时,你应该让你的视图尽可能愚蠢(关于视图和业务相关组件的耦合)。在最好的情况下,它们不应包含任何业务逻辑。这意味着他们也不应该知道任何关于业务对象(模型)的信息。只要您在self.StatusLabel.text = self.statusObject.message;中的statusObject不是数据传输对象,让单元格自行检索其值就不是一个好主意 - 因为这样这些单元格就需要了解您的模型结构。

通常每个视图都有自己的视图控制器,但是 - 当然 - 您可以使用它们所需的功能来组合视图控制器。

例如

:如果某些视图控制器需要数据,您可以引入一个单独的(视图相关)组件来提供该数据(例如,通过创建和返回单元格)。此组件将提供您的模型数据(或数据传输对象),并将返回一个结构,可供所有需要这些信息的视图控制器使用。

最新更新