玉炜的iOS开发规范(12.14更新)


苹果账号篇


1、新建一个新项目之后的bundle ID无论是否定没定,上架的账号如果没定,最好先写一个绝对用不上的名字,因为这个bundle ID一经确定会被绑定在当前你的苹果账号上,如果正好绑定的是非开发者账号(换句话说就是没有交钱的账号)那这个bundle ID就只能跟着这个账号了(如果是开发者账号还可以挽救一下,因为可以上苹果开发者网站删掉)。


2、苹果开发者网站底部有更改语言为中文的选项,虽然整个网站不可能是完全汉化的,但是申请开发者账号时访问的网页基本上都是中文的,对英语苦手来说确实是一大福利。


3、如果你维护中的iOS项目因为各种莫名其妙的原因会长时间不能使用原有的开发账号,这个时候不仅会无法上架,甚至连真机调试也不能用,这个时候的应对方式就是将bundle id修改别的,然后用自己的apple账号(不是开发者账号也能用)运行就可以解决。


bugly使用指导篇

埋点是个好习惯,当网络请求失败的时候记得上传报错信息,相关代码:

        failure:^(NSString *errorMessage, int errorCode) {
            NSDictionary *reportDic = @{
                                @"errorMessage":errorMessage,
                                //其他错误
                                }.copy;
            NSException *exception = [[NSException alloc]initWithName:@"xxx"
                                                               reason:@""
                                                             userInfo:reportDic];
            [Bugly reportException:exception];
        }];

有时候,我们可能(其实也应该)当问题发生的时候都会想着一股脑的自定义上传一些全局信息(例如用户名、用户ID、搞不搞基等(咦?)),而人是很懒的,我们不希望每次都会重复输入又长又长的代码来上传这些信息,而且上一条的方法只是自定义上传的报错,当遇到崩溃的时候是不管用的。而bugly的delegate里面提供了一个方法:
- (NSString *)attachmentForException:(NSException *)exception ;
所以只要签订协议,并实现该方法即可

- (NSString *)attachmentForException:(NSException *)exception {
    NSDictionary *userDic = @{
                              @"hxId":@"xxx"
                              @"username":@"xxx",
                              @"userIdName":@"xxx",
                              @"userClassId":@"xxx",
                              @"userClassName":@"xxx",
                          };
    NSLog(@"用户相关信息:%@", userDic);
    NSLog(@"(%@:%d) %s %@",[[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, __PRETTY_FUNCTION__,exception);
    return @"This is an attachment";
}

动作交互篇

1、SVProgressHUD提示信息一般条件下应当这么使用用户体验最佳

    [SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeBlack];
    [SVProgressHUD showSuccessWithStatus: @"成功"];
    [SVProgressHUD dismissWithDelay:1 completion:^{
        [SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeNone];
    }];

即先把提示背景置为灰色(此时不可以点击其他),设定延迟1秒后消去(如果字数两行的话多延迟1秒,再长就用UIAlertViewController),然后又把提示背景设为为无。


2、确保SVProgressHUD不在UIAlertViewController中使用,因为不会出现。目前可行替代方案暂时是用UIAlertViewController。


UI篇

1、官方认为按钮宽高小于44的情况下按压下去是很难触发的,而实际情况下许多按钮比这个大小要小(日常黑美工),所以可用imageEdgeInsets属性来缓解触摸不灵的问题。


2、一般给按钮设定选择状态时的图片时一般都是这么做的

[btn setImage:[UIImage imageNamed:@"a1"]
                     forState:UIControlStateNormal];
[_pupilBtn setImage:[UIImage imageNamed:@"a2"]
                     forState:UIControlStateSelected];

然而这么做会出现一定的问题,用户在按键处于选择状态的时候长按(谁这么无聊)时,按钮立刻会显示为未选择的状态。
选择状态下长按
所以如果需要在高亮状态下保持原状的话代码应该这么写

[_pupilBtn setImage:[UIImage imageNamed:@"a1"]
             forState:UIControlStateNormal];
[_pupilBtn setImage:[UIImage imageNamed:@"a1"]
             forState:UIControlStateHighlighted];
[_pupilBtn setImage:[UIImage imageNamed:@"a2"]
             forState:UIControlStateSelected];
[_pupilBtn setImage:[UIImage imageNamed:@"a2"]
             forState:UIControlStateSelected | UIControlStateHighlighted];

【和后台相爱相杀篇】


每次进行新项目开发前与后台开发确定好返回错误,错误码(error code)和错误信息(error message)的key,并敦促后台一定千万要一直使用这个key。
——HTTPClient是公司iOS开发常用的用于发送网络请求的小型库,其与AFNetworking联动,可以针对请求成功和请求失败通过条件判断选择下一步的操作,这个在AFNetworking里虽有实现,但是其对正确、失败的判定依据多在于服务器是否返回数据,其中就存在着返回的数据明明在表达着“失败”却又被AFNetworking认定为“成功”的尴尬效果,HTTPClient就对此弊端进行了优化,在AFNetworking判定成功的前提下又增加了对错误码和错误信息是否存在的判定,完善了整个判定的正确性。以get请求为例,源代码如下:

            [manager GET:url parameters:params progress:NULL success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                NSDictionary *responseDict = (NSDictionary *)responseObject;
                int code = [responseDict[@"code"] intValue];
                if (0 == code && responseDict) {
                    if (success) {
                        success(responseObject);
                    }
                } else {
                    NSString *errorMessage = responseDict[@"msg"];
                    if (failure) {
                        failure(errorMessage, code);
                    }
                }
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                [SVProgressHUD dismiss];
                NSString *errorMsg = [error localizedDescription];
                if (failure) {
                    failure(errorMsg, (int)error.code);
                }
                DebugLog(@"GET Request error:\n %@", errorMsg);
            }];

看得出代码虽然成功实现了预期的功能,但是弊端也是有的,此代码只是通过是否存在”code”、”msg”来进行判定,所以与后台沟通的时候一定要确定好是否要用这两个key。


iOS 11适配遇坑篇


scrollView可能会有些坑,比如说tableview reloadData时会可能出现瞬移的现象。遇到这种情况的解决方法如下

if (@available(iOS 11.0, *)) {
    self.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    self.scrollView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
    self.scrollView.scrollIndicatorInsets = self.scrollView.contentInset;
} else {
    self.automaticallyAdjustsScrollViewInsets = YES;
}

注意,scrollView在iOS 11出现的时候需要先用以前的版本测试是不是在以前的版本也会出现,如果以前的版本也出现的话就说明这根本就不是iOS 11的锅,毕竟人家库克再怎么gay也是有gay力来统帅苹果的,干嘛什么事情都怪人家。


iOS 11还有个坑的地方就是导航栏的titleView,比如说我们要在导航栏中间加个什么搜索栏的时候通常都会用到如下语句。

self.navigationItem.titleView = titleView;

这个时候可能会出现按理说长条的搜索栏会长成了天眼(图日后补)。
这个时候就要做适配。

if(@available(iOS 11.0, *)) {
    [[self.titleView.heightAnchor constraintEqualToConstant:<#高#>] setActive:YES];
    [[self.titleView.widthAnchor constraintEqualToConstant:<#宽#>] setActive:YES];
}

相关