开发路上踏过的坑

——只灯片笺


此文记录的是笔者在实际iOS开发工作中遇到并解决的一些小细节问题,以此记录,持续更新,仅供参考。

  • Gzip和POST请求相关问题

1.导入头文件(Ps:此处的是AFNetworking3.0)

#import "AFNetworking.h"
#import "AFgzipRequestSerializer.h"

2.封装网络请求:

-(void)request:(NSString *)url dic:(id)parameter success:(SuccessBlockType)successBlock failed:(FailedBlockType)failedBlock {
    
    NSString *urlEncoded = [self urlEncode:url];
    
    AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]init];
    
    //增加一种类型,text/html类型
    NSSet *set = manager.responseSerializer.acceptableContentTypes;
    NSMutableSet *acceptSet = [NSMutableSet setWithSet:set];
    [acceptSet addObject:@"text/html"];
    [acceptSet addObject:@"text/xml"];
    [acceptSet addObject:@"text/json"];
    [acceptSet addObject:@"text/plain"];
    manager.responseSerializer.acceptableContentTypes = acceptSet;
    
    //  用以解决bug:NSURLErrorDomain code -1012
    [manager.securityPolicy setAllowInvalidCertificates:YES];
    
    //  接受gzip压缩的json(普通的)
    [manager.requestSerializer setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
    //  或者是:(服务器端返回的)
    [manager.requestSerializer setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"];
    
    //  将parameters 进行压缩
    manager.requestSerializer = [AFgzipRequestSerializer serializerWithSerializer:[AFJSONRequestSerializer serializer]];
    
    //添加此方法,解决未注册的https无法忽略的问题   warning:In order to validate a domain name for self signed certificates, you MUST use pinning.
    manager.securityPolicy.allowInvalidCertificates = YES;
    manager.securityPolicy.validatesDomainName = NO;
    
    [manager POST:urlEncoded parameters:parameter progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        //把解析好的数据,即网络返回的数据,通过block回传回去
        if (successBlock) {
            successBlock(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if (failedBlock) {
            failedBlock(error);
        }
    }];
}

3.Gzip解决的关键代码:

    manager.requestSerializer = [AFgzipRequestSerializer serializerWithSerializer:[AFJSONRequestSerializer serializer]];

4.当然,上面的操作完毕后,编译,会提示这样的错误:


img_eb1af7cea19e0ecc5175544eb2019fea.png
Error.png

错误的意思是:你有两个相同的.m文件,然而,实际上一个相同的也没有。
此处仅仅是没有导入系统文件而已。
导入即可。


img_0f0ef9bbf08cc393de83e60ca2df082f.png
debug.png
5.一些多余的废话,全当是注解。
以上步骤均完成后,在后续调用的时候,POST的请求体内的键值对就会被Gzip打包压缩。

发送给服务器后,就会在服务器端解压缩,获取到请求体,从而服务器响应请求内容,反馈给你Gzip后的请求数据。
用AFNetworking封装的Block网络请求,会自动接受服务器Gzip后发送过来的数据。


  • TableViewCell的点击

默认状态下,点击cell后的状态是这样的:


img_e7835769ba96b7bdc101304feb6878b1.png
默认状态.png

而我们可能希望是这样的(没有选中的那个浅灰色提示):


img_a78fd1db1eb7a88dd81cb79709a7f95f.png
我们希望的.png

所以,可以通过在代理方法中,输入一段代码即可。
关键代码如下:
//  选中Cell的方法
#pragma mark - 选中Cell的方法
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //  点击后,取消当前的选中状态
    [tableView deselectRowAtIndexPath:indexPath animated:NO];
}

  • NavigationController全屏返回

我们知道,NavigationController自带有滑动回到上一级的功能。
但是,当屏幕太大的时候,我们可能希望,随便滑动视图上某个位置就可回到上一级。
1.导入头文件

#import <objc/runtime.h>

2.关键代码部分:

//弄全屏
-(void)startFullScreen {
    //  获取系统自带滑动手势的target对象
    id target = self.interactivePopGestureRecognizer.delegate;
    
    //  创建全屏滑动手势,调用系统自带滑动手势的target的action方法
    UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
    
    //  设置手势代理,拦截手势触发
    pan.delegate = self;
    
    //  给导航控制器的view添加全屏滑动手势
    [self.view addGestureRecognizer:pan];
    
    //  禁止使用系统自带的滑动手势
    self.interactivePopGestureRecognizer.enabled = NO;
}
//  什么时候调用:每次触发手势之前都会询问下代理,是否触发
//  作用:拦截手势触发
-(BOOL)handleNavigationTransition:(UIGestureRecognizer *)gestureRecognizer {
    //  注意:只有非根控制器才有滑动返回功能,根控制器没有。
    return YES;
}
//  代理方法
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    //  判断导航控制器是否只有一个子控制器,如果只有一个子控制器,肯定是根控制器
    if (self.childViewControllers.count == 1) {
        //  表示用户在根控制器界面,就不需要触发滑动手势
        return NO;
    }
    return YES;
}

  • 点击按钮无法显现预期效果

有些时候,我们可能会遇到按钮点击后无法执行出一些预设的效果的状态。
但是,如果,我们打印一句话,却能显示出来。
此时,可能,你的代码里,出现了条件判断语句中嵌套了条件判断语句的状态。

就好像像这样:
if ([respondData[@"RS"] length] < 10) {
    //  判断是否能在错误信息中找到"password is wrong"
    NSRange range = [respondData[@"ROWRS"] rangeOfString:@"password"];
    //  如果能找到,则range.location != NSNotFound
    if (range.location != NSNotFound) {
      UIAlertController * currentAlert = [CECAlertEngine alertShow:@"密码错误"];
      //  弹出提示框;
      [self presentViewController:currentAlert animated:true completion:nil];
    }else {
      UIAlertController * currentAlert = [CECAlertEngine alertShow:@"该账户尚未注册"];
      //  弹出提示框;
      [self presentViewController:currentAlert animated:true completion:nil];
    }
}

而这里,我们要做的是拆分出来条件判断语句中嵌套的条件判断语句,并加之return。
如此一来,就可以解决标题所述问题。

推荐这样:
//  判断是否能在错误信息中找到"password is wrong"
NSRange range = [respondData[@"ROWRS"] rangeOfString:@"password"];
//  如果能找到,则range.location != NSNotFound
if ([respondData[@"RS"] length] < 10 && range.location != NSNotFound) {
    UIAlertController * currentAlert = [CECAlertEngine alertShow:@"密码错误"];
    //  弹出提示框;
    [self presentViewController:currentAlert animated:true completion:nil];
    return;
  }
  else if ([respondData[@"RS"] length] < 10 && range.location == NSNotFound) {
    UIAlertController * currentAlert = [CECAlertEngine alertShow:@"该账户尚未注册"];
    //  弹出提示框;
    [self presentViewController:currentAlert animated:true completion:nil];
    return;
}
总的来讲,尽一切可能避免条件判断语句中嵌套条件判断语句。

  • AutoLayout下UIScrollView无法滚动问题
此处采用的是Masonry进行的约束。
为什么会出现这个问题?

使用支持AutoLayout后,在ViewDidLoad之后,系统会重新计算控件的一些值,导致之前你所设置的contentSize被重置为(0,0)了。

解决方案很简单:把设置contentSize的代码放到viewDidAppear上即可。
//解决AutoLayout下ScrollView无法滚动问题
-(void)viewDidAppear:(BOOL)animated {
    //  设置滚动视图的滚动范围
    self.baseScrollView.contentSize = CGSizeMake(kSceenWidth, (kSceenWidth * 279 / 990) + 534);
    [super viewDidAppear:animated];
}

修正:AutoLayout下UIScrollView无法滚动问题 最新最好的解决办法
将所有的添加载scrollView上的控件,顺序调整下,即可。
1.声明scrollView,并添加到视图。
2.添加其余控件到scrollView上。
3.用Mansory进行AutoLayout布局。
示例代码如下:

-(void)viewDidLoad {
    [super viewDidLoad];
    
    UIScrollView *baseScrollView = [[UIScrollView alloc] init];
    [self.view addSubview:baseScrollView];
    
    //maskView 这一段代码 可以注释掉 不影响效果
    UIView *maskView = [[UIView alloc] init];
    [baseScrollView addSubview:maskView];
    [maskView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(baseScrollView);
    }];
    
    UILabel *testLabel = [[UILabel alloc] init];
    testLabel.numberOfLines = 0;
    [maskView addSubview:testLabel];
    [testLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(maskView).offset(10);
        make.top.equalTo(maskView).offset(10);
        make.right.equalTo(maskView).offset(-10);
    }];
    
    testLabel.text = @"此处自行写一段长长的文字做测试即可";
    
    UIImageView *imageView = [[UIImageView alloc] init];
    imageView.backgroundColor = [UIColor cyanColor];
    [maskView addSubview:imageView];
    [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(testLabel.mas_bottom).offset(10);
        make.left.equalTo(baseScrollView).offset(10);
        make.right.equalTo(baseScrollView).offset(-10);
        make.size.mas_equalTo(CGSizeMake(300, 300));
    }];
    
    [baseScrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
        make.bottom.mas_greaterThanOrEqualTo(imageView.mas_bottom).offset(20);
    }];
}

  • iOS关于SVN冲突问题
iOS关于SVN冲突问题:
Project /Users/XXX/Desktop/XXX/XXX/xxx.xcodeproj cannot be opened because the project file cannot be parsed.
解决方法的步骤:

1.在文件夹中找到 xxx.xcodeproj 文件,点击右键,选择显示包内容
2.双击打开 project.pbxproj 文件
3.找出冲突信息(用commad + f 快速搜索)
4.删除 <<<<<<< ====== >>>>>> 这些行(hang)
5.保存,退出 (有时要clean 一下))
6.重新打开xxx.xcodeproj文件即可


  • 在一堆条件判断中做弹窗提示
img_2f87437be306a0f7addef0f3c2503250.png
弹窗警告.png
遇到的问题是,如果不正确写好逻辑,就会一直报错,说是弹窗已经提前声明显示过了,不过是空的。而实际的程序并没有任何异样。
后来,修改逻辑后就好了。所以,尽信书,不如无书。禅与Objective-C讲到的一些东西是有用。但是,更要结合自己的实际。
所以,该用这样
    if ( ) {
        
    }
    else if ( ) {
        
    }
    else {
        
    }

  • 图片不显示的问题

如果,某天,你一脸懵逼的发现,你的图片刚开始测试的时候是显示的。但是,后来突然某天抽了,不显示了。

而且,你的写法是这样的:
[UIImage imageNamed:@"18"];
所以,当你郁闷的时候,不妨看看,这样的写法:
[UIImage imageNamed:@"18.jpg"];

其实,这里的问题很简单,因为iOS对.jpg格式的图片支持并不是很好,如果是.png格式的图片,则是毫无问题。所以,当你的图片格式是.jpg格式,请把名字写全。免得郁闷自己。


  • 环信集成问题

最近在做即时通讯,需要集成环信的SDK,但是,环信的SDK真的挺老的。
按照官方文档走,即可。

需要注意的是,别看错文档。好几次,我看着文档郁闷半天,才发现自己看的是2.0的文档。所以,要看的话,请看3.0文档。

xxx.pch文件里,不要导入环信的头文件,否则会运行失败,一堆的Error。

So,尽可能避免在pch头文件内一次性导入过多的.h文件,否则会出现莫名其妙的重复文件问题。
确切的做法是:在需要用到的地方进行引用.h文件即可。可以避免一些不必要的麻烦出现。

一般错误提示为:

ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
这里的错误提示。
前一句意思是:你缺失libssl这个库文件。
后一句的意思是:你有两个重复名字的文件。
以第一句为基准,因为曾经以第二句为基准,差点被坑惨。

修正,最新解决方案:
实际上,可以丢在头文件里,只是需要注释掉一部分东西,再添加一部分东西即可。也就是几行代码的问题而已。


img_d60c03c65b75a9f4e5d6c4cc5c01a799.png
EMSDK.h.png

img_4152d098ca87eda7719b091fe1df7bd3.png
EMSDKFull.h.png
按照图中注释掉后,即可。
接着,集成环信的UI界面,步骤如下:

1.到官网的SDK现在最新的iOS SDK。
网址:
http://www.easemob.com/download/im

img_9696630d4e3733ce682e726b1e88f4d1.png
46E61F1B-441D-4FF2-A494-348471E75093.png

2.EaseUI使用指南中下载EaseUI工程。
网址:
http://docs.easemob.com/im/300iosclientintegration/85easeuiguide#easeui_使用指南
img_3393344b1dd351943e0c1a6995c4e223.png
AC27D33B-12A6-467E-A149-B0D1D064A79D.png

3.打开下载的文件夹,从中拖需要的文件到自己的工程内。

EaseUIResource.bundle
img_6ce4d36ca72d4877e345e5bc5807da3c.png
最新的SDK中提取.png
EaseUI
img_f2a3e1f3ef4058dd64670573bc394494.png
EaseUI.png
Resource
img_6f06275cca0f7135105196d53f0ea73f.png
UI图片资源.png

此时编译,会有一堆什么runtime之类的报错。
需要在pch文件里的首尾部分,添加如下代码:


img_7ec7ecb27fe2cabcb7b4e4824794d9b6.png
添加框中代码.png

余下的还有error,请自行解决。
我在开发中遇到的问题是MBProgress之类的东西的error,注释掉error部分就行了,良好运行,简单粗暴。


  • SVN命令行将工程导入到服务器

另注:SVN首次从本地导入到SVN服务器的时候,有时可能不支持http协议。

打开终端,输入如下命令行:
svn import /Users/cecdata/Desktop/08.12/DoctorApp https://xxx.xxx.xx.xxx/svn/xxxxx/ --username=xxxxx --password=xxxxx -m "修改了注册页的弹窗提醒,并继承过环信SDK,调试bug完毕"

  • 极光推送SDK集成问题
极光推送相对环信,更加简单点。但是,需要配置证书。特别是描述文件。
遇到的问题是这样的。推送测试消息,成功。但是接收数为0。
后台打印是这样的。
img_2102bce1be129b0a2bc1b701b8865ebc.png
后台打印.png
其实,这个问题解决,倒也简单。
只需要把配置好的描述文件(Provisioning Profiles)导进来(从开发者中心下载下来,双击安装即可)。需要注意的是,你必须保证你的工程中的Bundle Identifier跟开发者账号配置的AppID是一致的。否则,这也会是导致崩溃的原因。
因为引用了环信的SDK,所以,做了这样的操作。
SDK 不支持 bitcode,在 Build Settings → Linking → Enable Bitcode 中设置 NO。
如果进行了上面的操作,那么接下来就该这样操作。
img_53077f8f231fff138bfec0842ff19e83.png
应该这样.png

img_dbc675a63504a042428abe1118633990.png
路径.png
另:需要注意,从钥匙串导出的.p12文件,尽可能为英文或者数字命名,否则,也会不定性错误。
 集成完极光SDK,出现这样的后台打印。
img_e733e4d85de9f4ac977dd430fec1c485.png
后台打印.png
这里的错误提示很简单。就是告诉你,约束错了。我什么都没干,哪来的约束错误。不搭理它,重新换个真机运行,毫无问题。再换回来,也是毫无问题。就这样,问题解决了。所以,尽可能,clean一下,再运行。

  • scrollView高度动态变化

近来做项目,遇到需要根据scrollView上添加的视图控件的高度动态变化状况,来对scrollView的高度进行动态变化。

此处,显而易见的就会想到AutoLayout。原理很简单,就是在scrollView添加一层类似于蒙版层的东西,填充scrollView (当然,你也可以不加这一类蒙版层)。不过,个人感觉,为了稳妥起见,添加为好。特别是用xib的小伙伴们。

从网上也看了颇多,挺麻烦。就想着自己简化来写。
此处示例的是一个小测试demo的全部代码。

//引入Masonry头文件
#import "Masonry.h"
-(void)viewDidLoad {
    [super viewDidLoad];
    
    UIScrollView *baseScrollView = [[UIScrollView alloc] init];
    [self.view addSubview:baseScrollView];
    [baseScrollView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
    }];
    
    //maskView 这一段代码 可以注释掉 不会影响高度动态变化以及滚动效果
    UIView *maskView = [[UIView alloc] init];
    [baseScrollView addSubview:maskView];
    [maskView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(baseScrollView);
    }];
    
    UILabel *testLabel = [[UILabel alloc] init];
    testLabel.numberOfLines = 0;
    [baseScrollView addSubview:testLabel];
    [testLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(baseScrollView).insets(UIEdgeInsetsMake(20, 10, 0, 10));
    }];
    
    testLabel.text = @"/*此处,请自己动手,写一段特别长的文字,来用做测试*/";
}

  • The file * couldn't be opened because you don't have permission to view it.

当你休息了一个周末回来,打开你的工程,跑起来,却莫名其妙的报了这样的错误:“The file * couldn't be opened because you don't have permission to view it”错误信息。
你一定非常纳闷,哪里出问题了,明明你上周五离开的时候,还是运行良好无误的。

解决方案:

Window --> Projects --> 在下面框框左面选择你的项目名字 --> 在右面有一个delete,点击删除即可。不会影响你的文件,删除后相当于从0编译第一次速度会慢一点而已。


img_affcb812c48ce525144abbd6749305a1.png
解决问题.png

  • 蒲公英上传打包出现的问题:
Error:
Provisioning profile does not match bundle identifier: The provisioning profile specified in your build settings (“xxxxxxxxx”) has an AppID of “com.xxx.xxxxxx” which does not match your bundle identifier “com.xxx.xxxxxx.xxxxx”.
解决方案:
img_3abec9251798f3cffc02bd0e2d624be7.png
错误解决方法️①.png

img_21f75aaa02a8d681a71356c6395695a3.png
错误解决方法️②.png

  • 缓存未清除问题:
Error:
ld: warning: directory not found for option '-L/Users/xxx/Desktop/xxxxxx/xxx/xxx/Classes/IMSDKLib/HyphenateFullSDK/lib/3rdparty'
ld: warning: directory not found for option '-L/Users/xxx/Desktop/xxxxxx/xxx/xxx/Classes/IMSDKLib/HyphenateFullSDK/lib'
ld: warning: directory not found for option '-L/Users/xxx/Desktop/xxxxxx/xxx/xxx/Classes/EaseUI/EMUIKit/3rdparty/DeviceHelper/VoiceConvert/opencore-amrnb'
ld: warning: directory not found for option '-L/Users/xxx/Desktop/xxx/xxx/xxx/Classes/EaseUI/EMUIKit/3rdparty/DeviceHelper/VoiceConvert/opencore-amrwb'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
img_be8c6d1dc3cc5c57144188d7afcba8b9.png
错误.png
解决方法:
红色框内,全部清除掉,即删掉编译报warning的路径即OK
img_73b09995b44d1c457d0de9193c6721ea.png
解决办法️.png

img_217139ea695c8b1ffecd5837d315a1af.png
解决办法️.png

  • 环信集成的错误:ld: library not found for -lopencore-amrwb

编译阶段就会报这样的错。
解决办法:

project->general->linked frameworks and Libraries
找“ -lopencore-amrwb” ,然而,实际是找不到的。因为,其对应的是:libopencore-amrwb
img_be08383d6078849a22ccfa4014173bd5.png
解决办法️.png
红色框内为细节注意问题

点击之后,你会发现,这个文件在文件夹内是实际存在的。
接下来的解决方法就是:

把它丢出工程外,但是要注意,不是丢到垃圾篓。
img_6951d38efad89f996cc03513d414794a.png
解决办法️.png
然后,选中你要添加进的文件夹。按快捷键alt + command + A,会打开finder,选择你刚才移除的文件夹,点击Add,即可。
之后,之前报错的路径问题,就可解决。估摸着,应该是 linked frameworks and Libraries 会自动更新的缘故。

  • 关于Xcode 8创建的storyBord、Xib在Xcode 7中无法打开的问题

错误是这样的:

This version does not support documents saved in the Xcode 8 format. 
Open this document with Xcode 8.0 or later.
img_faaf89c68a97bc03cad2bea45b810e95.png
StoryBord错误.png

img_c2f2e6421a293a083a2d51b09224db23.png
XIb错误.png

解决办法:

对于StoryBord:
可以用文本编辑器打开xib文件,将document中的toolsVersion和plugln中的version改正原来xib文件中的值,同时删除
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"
对于Xib:
用编辑器将Xib里面的下面一句话删除掉才能打开:
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>

  • Xcode编译错误:ld: 5 duplicate symbols for architecture arm64

错误是这样的:

ld: 5 duplicate symbols for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

解决办法:

Xcode编辑时报:2 duplicate symbols for architecture arm64
1.查看自己项目中是否有重复命名的文件
(一般就是这个问题,如果项目中排查后,没有发现。
那就该项目所在的文件是否有重复命名的文件,删除一个就可以了,排查的目标一般都在报错前面列举出来。)
2.再查看是否在编辑#improt头文件时候,不小心把.h误写成.m

  • iOS·SVN出错
iOS:SVN出错 Description : The working copy is locked due to a previous error
错误打印如下:
Description : The working copy is locked due to a previous error. Suggestion : Clean the working copy and then retry the operation. Technical Information 
===================== Error : V4WorkingCopyLockedError Exception : ZSVNWorkingCopyLockedException Causal Information ================== 
Description : Working copy '/Users/cecdata/Desktop/SmartGoBeta/SmartGo_IOS' locked. 
Status : 155004 Description : '/Users/cecdata/Desktop/SmartGoBeta/SmartGo_IOS/SmartGo_Simple_3.0' is already locked. Status : 155004
解决方法如下:

使用CornerStone工具update最新SVN代码报错:The working copy is locked due to a previous error,不仅无法上传,也无法更新,错误提示被锁。

解决方法:在CornerStone找到本地代码工程--右键--点击clean 即可。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值