常用开发技巧系列(五)

前言


前面刚发了这个技巧总结系列的第四篇文章,这篇文章总结的一些日常开发中的技巧或更偏向于Cocos2d方向,因为最近在游戏中有原生的一个客服系统需要加进来,就涉及到一个游戏和原生界面的交互以及各种各样的BUG,游戏是属于在别人代码的基础上进行的二次开发,属于一个非ARC的情况,而我们现在的三方应该都是ARC,还有那些让人头疼的屏幕旋转键盘等等的问题,最近爬的坑有点多,所有这篇就主要来总结这些坑!当然在我们的普通应用中遇到这些问题我们还是同样可以依照这些技巧总结的。

一:__weak typeof(self)报错了


这个问题我也是觉得奇怪,在我们正常的使用中一般是不会出现这种错误的!这个一般是绝大多数的情况,应该和这游戏源码的年代有直接的关系,这个错误我也截图了,如下:

这个问题出现的时候上网找了一下解决的办法,解决是很简单就能解决这个问题,只要是和我的在 build setting 中下面的设置项不一致,你把它改成一致的即可:

前面说了,这个解决起来很简单,但是我们不明不白的设置这东西就是属于稀里糊涂了:

二: 横屏切换竖屏


我们一般的游戏都是横屏的,当然也有竖屏的,在日常的需求中很有可能就涉及到游戏和原生界面的交互,就有了横屏游戏切换竖屏原生界面出来,其实最让人头疼的,是你切换界面之后还有键盘的问题!在自己的游戏中就有这样一个切换是在客服系统当中,横屏的游戏需要你切换到竖屏的一个客服聊天界面!其中就涉及到这个键盘的问题!我们再这里也总结一下在iOS应用中决定键盘的方向因素,在不同iOS版本中是不一样的。

iOS8:

键盘方向是根据一个特定的window决定,打印[UIApplication sharedApplication].windows,最少有两个,第一个为UIWindow,是程序主要的keyWindow;第二个为UITextEffectsWindow,是键盘所在的window。

iOS9:

键盘方向由最后一层window决定,这里有点复杂,因为iOS9新增了一个UIRemoteKeyboardWindow。那么应用可能就有3个window,依次是UIWindow,UITextEffectsWindow,UIRemoteKeyboardWindow。UIRemoteKeyboardWindow成为决定键盘方向的window了,而UITextEffectsWindow控制了键盘顶部栏的方向,如下如:

iOS10:

和iOS9类似,但是,如果要强制旋转键盘的话,它的坐标计算方法又和之前的系统有区别。区别在于计算window的原点坐标(x,y),iOS10是(0,0,width,height),iOS9的x和y需要这样计算:CGFloat keyBoardWindowXY = (viewSize.height - viewSize.width) / 2

具体的推荐大家看这篇:[iOS]终极横竖屏切换解决方案

这篇文章能解决大部分大家的需求。包括一些webView的屏幕旋转等等。

三:ARC和非ARC混编


有维护一个以前的Cocos-lua的游戏,这份代码也是比较的老了,是非ARC的环境,在维护中有给这个游戏当中添加其他第三方的框架进去,但现在的iOS的框架几乎没有非ARC环境的,就会有各种各样的错误,这时候你就的进行他们的混编了,其实单纯混编这一点设置很简单,关键的其实是我们得有这样的一个清晰的认知,知道这里需要ARC的环境,而不是你拉进去其他的三方之后看到报错,就一个劲的纠结在哪个错误上!!这才是我这里说这一点的最重要的东西,设置的的很简单,我直接截一张图给大家,相信都能看明白!

下面是你给游戏中添加了MJ之后,你把MJ设置成ARC环境:

四:无线真机测试


在iOS中我们经常会进行真机测试的,不知道小伙伴们是不是都找一根数据线然后连接上测试机之后测试的,有时候可能还得用自己的手机,一夸张一插就是一整天,谁都知道这样对手机电池不好....

其实我们是可以可以无线真机测试的,我估计也应该有很多小伙伴是知道的,按下面步骤就可以进行测试,很简单的,两张图搞定:

接下来如下:

是不是OK了。是的,要是手机已经设置了密码就OK了。要是测试的手机没有设置手机密码这时候就会提醒你 Passcode Required 那你就乖乖设置一个手机密码就可以啦!

:JS 和 Swift WKWebView 的最基本交互


这个点要是往大了说。可以写一篇原生和JS交互的文章,但以前我写过这样的文章,就不想在做重复的工作了,这里我们就提一下JS 和 Swift WK的交互,也是刚有一点点需求写了,就记录一下吧,代码具体的看下面,需要注意的地方我都写在代码里面了:

Swift 代码:

代码语言:javascript
复制
 //MARK: JS Swift 交互
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
  let Url = message.body
  //MARK: 唤起浏览器
  if message.name == "Model" {
                    
          let url = URL.init(string: Url as! String)
          //根据iOS系统版本,分别处理
          if #available(iOS 10, *) {
                  UIApplication.shared.open(url!, options: [:],
                                            completionHandler:nil)
          }else{
                  UIApplication.shared.openURL(url!)
          }
  }

}

NOTE: 需要注意的是记得在初始化WK的时候给WKWebViewConfiguration 添加交互的信息,不然会调用不成功的:

代码语言:javascript
复制
let webConfiguration = WKWebViewConfiguration()
// 给webview与swift交互起名字,webview给swift发消息的时候会用到
webConfiguration.userContentController.add(self, name: "Model")

JS 端的代码就简简单单的一句:

代码语言:javascript
复制
 window.webkit.messageHandlers.Model.postMessage("https://www.baidu.com")

NOTE: 这个Model其实就是一个你和前端相约好的一个identify,这样容易理解,不管是有些文章说的方法名也好还是要传值的对象也好,其实起的作用就是一个identify的作用!

OC调用JS方法最简单的就是: stringByEvaluatingJavaScriptFromString

JavaScriptCore也是完全可以的,这个我们就不细说,下面是我给webView写的一个类别代码:

代码语言:javascript
复制
-(void)callJavascriptMethod:(NSString *)methName andCallHandleComplete:(CallComplete)callComplete{

NSString * respondString = [self stringByEvaluatingJavaScriptFromString:methName];
if (!respondString || [respondString isEqualToString:@""]) {
    debugLog(@"OC调用JS方法:%@ 返回数据为空",methName);
}
NSData *respondData = [respondString dataUsingEncoding:NSUTF8StringEncoding];
NSError *err;
NSDictionary * respondDic = [NSJSONSerialization JSONObjectWithData:respondData
                                                    options:NSJSONReadingMutableContainers
                                                      error:&err];
if(err){
    debugLog(@"OC调用JS方法:%@ 返回JOSN解析出错",methName);
}else
    callComplete(respondDic);

}

NOTE: 这里你只需要注意一点,JS要有返回值,返回值只能是字符串!!当然也可以是JSON字符串,JSON就能满足一般的需求了,要是JS返回的是一个Objcet,对不起你没办法处理!你可以叫JS把对象处理成JSON字符串给你。

六:AppDelegate 怎么弹出 UIAlertController 提示


不知道一些朋友会不会有这样的需求产生,需要你在AppDelegate中提示一些信息,可能许多人都会想到这句代码:

代码语言:javascript
复制
self.window?.rootViewController?

首先可以肯定的是肯定和这句是有关系的,这个无可争议!但关键点可能还不是在这里,你要直接添加我相信你log中会有这么一句:

Warning: Attempt to present <UIAlertController: 0x10684d200> on <PCDD.ViewController: 0x106014100> whose view is not in the window hierarchy!

这句话我们说的直白点的意思就是你要present UIAlertController的ViewController还不在当中

解决这个问题在stackoverflow有这样的答案 stackoverflow解答 最后我们直接上代码:

代码语言:javascript
复制
DispatchQueue.global().async {
DispatchQueue.main.async {
let alertCtr = UIAlertController(title: "连接错误", message: "请检查网络或者请求配置是否正确", preferredStyle: .alert);
alertCtr.addAction(UIAlertAction(title: "确定", style: .default, handler: { (action) in

            }))
            self.window?.rootViewController?.present(alertCtr, animated: true, completion: nil)
     }

}

七:禁止某一个控制器侧滑


其实你不用写太多代码的,你获取一下导航栏测滑动target,然后你把它action置一下nil就可以了

代码语言:javascript
复制
    // 禁止侧滑返回
id traget = self.navigationController.interactivePopGestureRecognizer.delegate;
UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc]initWithTarget:traget action:nil];
[self.view addGestureRecognizer:pan];

八:XCode 10 CocoaPods 升级 bad response Not Found 404 问题


我们在升级了Xcode10之后使用CocoaPods,在执行了pod install 之后就出了问题:

代码语言:javascript
复制
RuntimeError - [!] Xcodeproj doesn't know about the following attributes {"inputFileListPaths"=>[], "outputFileListPaths"=>[]} for the 'PBXShellScriptBuildPhase' isa.

因为 inputFileListPathsoutputFileListPaths 是 Xcode 10 中新增的属性, 因此旧版本的 CocoaPods 无法解析,所以我们升级CocoaPods,结果一般 gem 源是 ruby 中国都会出现这个问题,以为它换域名了:

它重新提供 .com 代替 .org 的域名,其他一切不变!所以我们换一下域名就OK了。终端中执行:

代码语言:javascript
复制

要是又出现没有写入的权限提示,You don't have write permissions for the /usr/bin directory. 这是在说/usr/bin 没有写权限, 这是由于 macOS 10.11 之后增加了 rootless 机制, 导致即使在 root 权限下依然无法修改文件. 解决办法,即修改 CocoaPods 安装目录:

代码语言:javascript
复制
sudo gem install cocoapods --pre -n /usr/local/bin

最后你可以查看一下自己pod版本是否升级成功: pod -- version