工作中的坑

1.通过xib加载的控件在viewDidLoad 中重新计算布局不准确的问题

在爱山门实时上门模块,由于之前没有加网络提示器或者没网的空白页之类的,在网络情况差的情况下,直接就是一个空白页放在那里,用户体验特别不好,所以这里需要加上一个网络的提示器在加载的时候进行弹窗提示用户,记载成功的话就直接显示数据,失败的话就提示网络问题。这个直接用SVProgress就可以。由于这里的界面布局比较固定,所以最好可以再做一个本地缓存,利用FMDB将上一次的数据存到本地,下次打开的话先从数据库去获取数据,没有的话再去网络请求。这里遇到了一个问题,折腾了大半个上午。就是每次通过本地缓存去加载数据的时候滑动范围总是不准,在viewDidLoad中已经计算好了scrollView 的高度和tableView 的高度,但是在viewDidDissAppear 中再去打印的话会发现尺寸并不是我们计算的那个结果。下拉刷新或者直接去加载网络的数据的时候就没问题。后来一直调试查找猜测应该是xib 的问题,因为这里的scrollView 和 tableView 都是通过xib 去加载的,通过xib 加载的文件在viewDidLoad中加载的时候并不会去布局frame ,只是拿到xib 中设置的大小属性,只有在 viewDidLayoutSubViews 里才会去根据布局去确定控件的最终尺寸(不过添加view 的操作不能放在这里,因为这个方法会调用多次)


2.导航栏隐藏 push 到下个界面再手势返回的时候显示和隐藏的问题。如下:
before.gif

好多项目中都会有这样的需求,导航栏透明或者隐藏,但是push 到下一个界面,如果用手势返回的话就会出现如上的问题,

比如积分商城
个人中心界面需要隐藏导航栏,设置如下:

- (void)viewWillAppear:(BOOL)animated
{
     [super viewWillAppear:animated];
     
     [self.navigationController setNavigationBarHidden:YES animated:animated];
     
     [self getCenter];
}

点击积分商城需要显示导航栏,设置如下:

- (void)viewWillAppear:(BOOL)animated
{
     [super viewWillAppear:animated];
     
//     [Glob showTabBar];
     
     [[self rdv_tabBarController] setTabBarHidden:YES animated:YES];
     
     [self.navigationController setNavigationBarHidden:NO animated:YES];
}

如果只是这样设置的话手势返回的话就会出现上面的问题。网上找了各种资料和三方库,比如 让我们一次性解决导航栏的所有问题
,由于之前项目中使用的tabBar 是 三方的RDVTabBarController,所以用上面文章中的三方总会出先手势返回的时候上一个控制器被一个空白的UIView挡住的情况。所以又开始找其他的同样不是很完美。最后抱着瞎猫碰死耗子的心态,就试试网上的一些建议,采用如下写法,在积分商城界面加上如下代码:

- (void)viewWillDisappear:(BOOL)animated
{
     [self.navigationController setNavigationBarHidden:NO animated:YES];
     [super viewWillDisappear:animated] ;  // 切记要加这个,不然没效果
}

一开始在一个空白的项目中做了测试,这样确实是可以了,但是放到公司项目却还是没用,一开始怀疑是 [super viewWillDisappear:animated]方法应该放在最后调用,后来测试放在前面和后面都没区别。最后发现问题是在个人中心界面,一开始个人中心界面隐藏导航栏的时候,动画那块设置的是NO:

[self.navigationController setNavigationBarHidden:YES animated:NO];

最后改成如下:

[self.navigationController setNavigationBarHidden:YES animated:animated];

至于这里的animated 写成 没有写成YES OR NO 是因为在网上看到过系统返回的属性不只是这两个(虽然我也不懂)不过这里animated 写成YES 也可以。

发现可以正常使用了。效果如下:

hhhh.gif

Perfect!
更新
后来发现只需要在个人中心设置

 [self.navigationController setNavigationBarHidden:YES animated:animated] // 这里animated 写成YES 也可以

不用再在其他界面再添加

- (void)viewWillDisappear:(BOOL)animated
{
     [self.navigationController setNavigationBarHidden:NO animated:YES];
     [super viewWillDisappear:animated] ;  // 切记要加这个,不然没效果
}

也一样可以实现效果

3.使用字典转模型的时候遇到崩溃 NSInvalidArgumentException -[__NSTaggedPointerString unsignedLongLongValue]: unrecognized selector sent to instance

这个问题,是因为64bit中,NSString 中没有unsignedLongLongValue这个方法了, 而当字典中obj的类型是NSString类型,实体中的key对应的属性是NSUinteger类型,setValue:obj forKey:key 会自动做如下处理:
[obj unsignedLongLongValue] 将value转为对应的属性类型,这就导致64bit中找不到该方法而crash。解决是,对NSString写一个category,重新写一个unsignedLongLongValue的方法:

-(NSUinteger)unsignedLongLongValue {
   return [self integerValue];
}

或者 避免 让系统做NSString->NSUInteger的类型装换

4. app后台被kill掉之后收到远程推送播放提示音乐

项目中有个需求,就是在锁屏界面收到有订单的情况下,除了有推送弹窗之外,还得加上一个语音播报的功能。这个功能是之前项目中就有的。但是有市场人员反映他的手机锁屏状态下只能收到推送消息,并没有语音提示,但是手机连接上Xcode 并锁屏进入后台模式下测试是可以收到语音提示的。所以怀疑是后台被杀死的原因。于是将APP彻底退出,然后再测试,确实收不到。再将APP打开,然后退到后台,锁屏再次测试,又可以收到语音提示。

iOS的APP采用的是假后台模式,当应用退到后台后,只有5s的时间去执行代码,之后将进入挂起状态。只有像音频播放、定位、newsstand、VoIP等功能才能持续在后台运行。但是开发其它应用是我们可以通过申请后台,来获得3分钟的后台执行代码时间(iOS7以前是10分钟)。

应用程序状态:

  • Not running 未运行
    • 程序没启动
  • Inactive 未激活
    • 程序在前台运行,不过没有接收到事件。在没有事件处理情况下程序通常停留在这个状态
  • Active 激活
    • 程序在前台运行而且接收到了事件。这也是前台的一个正常的模式
  • Backgroud 后台
    • 程序在后台而且能执行代码,大多数程序进入这个状态后会在在这个状态上停留一会。时间到之后会进入挂起状态(Suspended)。有的程序经过特殊的请求后可以长期处于Backgroud状态
  • Suspended 挂起
    • 程序在后台不能执行代码。系统会自动把程序变成这个状态而且不会发出通知。当挂起时,程序还是停留在内存中的,当系统内存低时,系统就把挂起的程序清除掉,为前台程序提供更多的内存。

iOS提供了两种方式唤醒处于挂起或已经被kill掉的app。分别是Silent NotificationVoIP Push Notification,客户端在被唤醒之后将获得30s的后台运行时间,这段运行时间足以请求合成语音数据并播放。

  • 1. Silent Notification: Silent Notification在iOS7以上便可以支持,但是每小时能推送的Silent Notification次数有限制。
  • 2.VoIP Push Notification VoIP Push Notification则是在iOS8以上才支持的新Push类型,相比于Silent Notification,VoIP Push具有高优先级、低延迟的优势,并且没有次数限制。 对比这两种技术方案,VoIP Push Notification明显更适合用于收款到账语音提醒的唤醒方案。

这里就需要用到 iOS VoIP (VoIP Push)业务来实现.具体的配置和思路参考以下引用。

由于里面好多的PHP的测试脚本不能运行,这里使用的是 PushMeBaby 来进行测试,具体的配置步骤:

下载好了之后,打开工程将voip_services.cer加入到工程里,修改token值跟证书路径,运行后会报错,将那一行直接改为#import ,再运行即可(没反应多运行几遍)。

- (id)init {
    self = [super init];
    if(self != nil) {
//注意token要带空格
        self.deviceToken = @"26f7b0a8 efa8e6b3 6dde46c5 8d1a2cf8 e3583e31 87feab7d af6c8a54 24896f55";
        self.payload = @"{\"aps\":{\"alert\":\"This is some fancy message.\",\"badge\":1}}";
        self.certificate = [[NSBundle mainBundle] pathForResource:@"aps_development" ofType:@"cer"];
    }
    return self;
}

作者:天明依旧
链接:http://www.jianshu.com/p/5ede7e6a8c90
來源:
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Refrence:
iOS VoIP (VoIP Push)开发集成
Example of iOS VoIP Notification / iOS VoIP Notification实例
微信iOS收款到账语音提醒开发总结
iOS消息推送之Voip 消息推送 服务器测试 PhP
iOS利用voip push实现类似微信(QQ)电话连续响铃效果

5.远程推送的时候,手机连接到Xcode的时候,APP进入后台模式可以正常调用 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler方法,但是Xcode断开之后,手机进入后台模式不会调用该方法。

解决方法:在手机连接Xcode的时候,手机会自动刷新。断开之后,如果手动设置了关闭 后台应用程序刷新,就不会调用到该方法。进入设置,将后台应用自动刷新打开,然后再测试,就可以正常调用了。
Refrence:

didReceiveRemoteNotification:fetchCompletionHandler当应用程序在后台未被调用,并未连接到Xcode

6. loadhtmlstring加载内容是不显示图片

内容页有图片标签,路径是相对路径,在本地显示的时候是去bundle里面找,除非本地有这个路径,不然就是显示蓝色小问号了。
解决方法,loadhtmlstring方法后面还有一个baseURL的变量,把图片或者网页的资源服务器路径传进去,就可以顺利找到这个路径。就相当于把不完整的image路径的前半部分传进去。

你可能感兴趣的:(工作中的坑)