• 【转】几点 iOS 开发技巧


    [译] 几点 iOS 开发技巧

    原文:iOS Programming Architecture and Design Guidelines

    原文来自破船分享

    原文作者是开发界中知晓度相当高的 Mugunth Kumar,他是 MKNetworkKit 的作者(虽然没有 AFNetworking 使用那么广泛,但也是一个很棒的 Network Kit),更是最近流传甚广的《iOS 5/6 Programming – Pushing The Limits》的作者。

    文章中 MK 介绍了几点开发中常用的小技巧,几条 Tips 简单易懂,但是很实用,不但可以提高开发效率,而且可以提高代码的可读性和可复用性。

    Types in Objective-C 和 Naming Conventions 两个章节介绍性内容较多,下面从 Subclassing 开始简单直译一下,第一次翻译,有诸多不到位的地方,各位多包涵。

    Subclassing 继承/子类

    大多语言允许开发者子类化框架所提供的类,但是在 Objective-C 中不完全是这样。大部分常用的类,诸如 NSArray、NSSet、NSDictionary 基本上都是集合类型的。不建议继承这些类,除非你准备转发调用或者实现所有必要的原始方法。

    在传统的开发语言中,通常会通过继承基础类型(类似 NSArray 的类)来新增方法,重载已有的方法,或是自定义 UI 组件的外观。在 Objective-C 中,一般通过 Category 来扩展新方法。通过混合方法(swizzling the method?)来重载 SDK 提供的实现。以及外观相关的代理协议(Protocol)来定制 UI 组件的外观。

    虽说如此,还是有一些类是经常会继承它们的,比如 UIViewController、UITableViewController、UIControl 等。继承 UIViewController 大概是开发过程中最棒的一件事,因为它使得添加常见的功能变得异常简单。在我开发的每个 App 中,会有一个继承自 UIViewController 的子类,它实现了一组常用的方法。所有其他的 View Controllers 则都继承自这个基础类。

    (译者注:Web 开发中也常会有一个用于被继承的 BaseController 来提供公共方法,看来开发是触类旁通的,要多思考)

    所以,以下继承方法:

    1
    
    @interface MyAppFeaturedYouTubeVideosViewController : UIViewController
    

    应该替换成:

    1
    2
    
    @interface MyAppFeaturedYouTubeVideosFeaturedViewController : MyAppViewController
    @interface MyAppViewController : UIViewController
    

    这个公用基础类可以在后续开发过程中用来添加公用的方法。在这个基础父类中,我通常会申明以下方法:

    1
    2
    3
    4
    5
    6
    
    -(UIView*) errorView;
    -(UIView*) loadingView;
    -(void) showLoadingAnimated:(BOOL) animated;
    -(void) hideLoadingViewAnimated:(BOOL) animated;
    -(void) showErrorViewAnimated:(BOOL) animated;
    -(void) hideErrorViewAnimated:(BOOL) animated;
    

    实现如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    
    -(UIView*) errorView {
      return nil;
    }
    -(UIView*) loadingView {
      return nil;
    }
    -(void) showLoadingAnimated:(BOOL) animated {
      UIView *loadingView = [self loadingView];
      loadingView.alpha = 0.0f;
      [self.view addSubview:loadingView];
      [self.view bringSubviewToFront:loadingView];
      double duration = animated ? 0.4f:0.0f;
      [UIView animateWithDuration:duration animations:^{
        loadingView.alpha = 1.0f;
      }];
    }
    -(void) hideLoadingViewAnimated:(BOOL) animated {
      UIView *loadingView = [self loadingView];
      double duration = animated ? 0.4f:0.0f;
      [UIView animateWithDuration:duration animations:^{
        loadingView.alpha = 0.0f;
      } completion:^(BOOL finished) {
        [loadingView removeFromSuperview];
      }];
    }
    -(void) showErrorViewAnimated:(BOOL) animated {
      UIView *errorView = [self errorView];
      errorView.alpha = 0.0f;
      [self.view addSubview:errorView];
      [self.view bringSubviewToFront:errorView];
      double duration = animated ? 0.4f:0.0f;
      [UIView animateWithDuration:duration animations:^{
        errorView.alpha = 1.0f;
      }];
    }
    -(void) hideErrorViewAnimated:(BOOL) animated {
      UIView *errorView = [self errorView];
      double duration = animated ? 0.4f:0.0f;
      [UIView animateWithDuration:duration animations:^{
        errorView.alpha = 0.0f;
      } completion:^(BOOL finished) {
        [errorView removeFromSuperview];
      }];
    }
    

    现在,App 中的每个 View Controller 中,可以很方便的通过调用以上方法来改变当前 View 的状态为 Loading 或者 Error。而且,View Controller 可以通过重载 -errorView 和 -loadingView 方法来提供自定义错误界面和 Loading 界面。

    你还可以通过重载这个基础类中的 -viewDidLoad 来统一修改所有 View 的表现。比如为所有的 View 添加相同的背景图片或背景色:

    1
    2
    3
    4
    5
    
    - (void)viewDidLoad
    {
      [super viewDidLoad];
      self.view.backgroundColor = [UIColor appOffWhiteColor]; // changes all my views to "off-white"
    }
    

    UI Customization 自定义 UI

    自定义 UI 可以大致分成两类,一是自定义控件,二是皮肤/主题。前者可以让 App 更出色,而后者是大部分 App 都需要的。我建议给 UIFont 和 UIColor 写 Category 扩展来提供自定义字体和自定义颜色。

    例如,给 UIFont 添加如下方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    +(UIFont*) appFontOfSize:(CGFloat) pointSize {
      return [UIFont fontWithName:@"MyriadPro-Regular" size:pointSize];
    }
    +(UIFont*) boldAppFontOfSize:(CGFloat) pointSize {
      return [UIFont fontWithName:@"MyriadPro-Black" size:pointSize];
    }
    

    你就可以很方便地使用 [UIFont appFontOfSize:13] 得到 MyriadPro-Regular 字体。这样当你的设计需求变更时,就可以很快速的更换整个 App 中的字体。

    相同的设计模式也可以应用到自定义颜色中。给 UIColor 添加以下方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    #define GREY(color) [UIColor colorWithRed:color/255.0 green:color/255.0 blue:color/255.0 alpha:1]
    +(UIColor*) appBackgroundColor {
      return [UIColor colorWithPatternImage:[UIImage imageNamed:@"BGPattern"]];
    }
    +(UIColor*) appBlack1Color {
      return GREY(38);
    }
    +(UIColor*) appOffWhiteColor {
      return GREY(234);
    }
    

    所以,千万不要用 Interface Builder 来选颜色。

    Subclassing UILabels 继承 UILabel

    还有一个小窍门,当开发者继承 UILabel、UITextField 和 UITextView 时,通常在 -initWithFrame: 和 -initWithCoder: 方法中设置字体和颜色,参见以下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    @implementation AppPrefixLabel
    -(void) setup {
      self.font = [UIFont fontWithName:@"SourceSansPro-Semibold" size:self.font.pointSize];
      self.textColor = [UIColor redColor];
    }
    -(id) initWithFrame:(CGRect)frame {
      if((self = [super initWithFrame:frame])) {
        [self setup];
      }
      return self;
    }
    -(id) initWithCoder:(NSCoder *)aDecoder {
      if((self = [super initWithCoder:aDecoder])) {
        [self setup];
      }
      return self;
    }
    @end
    

    这个技巧使得开发者可以在 Interface Builder 中自定义这些元素的外观。在 IB 中拖入一个 UILabel,并且修改它的类为你自定义的类,瞬间就完成了这个 Label 字体和颜色的自定义,不用任何多余的代码。

    这个技巧多数情况下相当管用,但是当你的 App 支持自定义主题,且用户可以通过设置界面更换主题时,就会显得有些麻烦。

    -initWithFrame: 和 initWithCoder: 会在 UI 组件创建的时候被调用,所以在这之后如果要改变字体和颜色,就需要很多额外的代码。因此,如果你的 App 支持主题,写一个主题管理器的全局单例来提供全局的主题、字体、颜色。

    如果你用到了我说的第一个方法,你的 UIFont 的 Category 现在可以这样实现了:

    1
    2
    3
    4
    5
    
    +(UIFont*) appFontOfSize:(CGFloat) pointSize {
      NSString *currentFontName = [[ThemeProvider sharedInstance] currentFontName];
      return [UIFont fontWithName:currentFontName size:pointSize];
    }
    

    UIColor 同理。其实没有正确或错误的方法,上述方法都是可行的。

    遵从这里提到的设计模式,可以让你的代码干净得像写的很漂亮的 JS/CSS。试着在你的下一个项目中用这些方法吧。

    Allen 后记

    之前在想 iOS 开发到底是否需要一个类似 Web 开发中的所谓的框架,但渐渐发现其实 iOS SDK 本就是一个高度封装了的框架了,可能我们需要的不是更更高层的框架,而是一种好的设计模式、开发习惯和代码结构。因此是不是可以从一个 Project 的层面出发,写一个干净的框架,并且定义一些规范,就是一个很好的“框架”了?而不是非得提供 Router 之类的往 Web 开发框架去靠。

  • 相关阅读:
    Webdriver启动Firefox浏览器后,页面显示空白
    Windows+Python+Selenium基础篇之1-环境搭建
    office2010无法卸载问题
    .NET使用FastDBF读写DBF
    并发编程相关概念
    C#的多线程简洁笔记
    asp.net core 3.1 入口:Program.cs中的Main函数
    【WPF学习】第四十四章 图画
    .NET知识梳理——1.泛型Generic
    C#个推SDK推送安卓+iOS
  • 原文地址:https://www.cnblogs.com/ymonke/p/3481469.html
Copyright © 2020-2023  润新知