一 简述
同为移动客户端,Android&iOS有着许多相似的地方,客户端开发的主要工作为界面编写,数据存储,网络请求等等, 作为开发者,Android&iOS所做的工作的基本原理的差不多的,这两个的开发思维基本相通。
二 例子
给一段object-c代码,及其错误日志,试着想出出错原因及解决办法。
目标:每秒显示斐波那契数列的新一位。
思路:
计算结果并把结果利用相关view显示。
在一顿搜索后,找出关键代码如下:
已知已下代码为切换到子线程:
dispatch_async(dispatch_get_global_queue(0, 0),
^{
// 这里是执行于子线程的代码块,可以用于处理耗时操作, 类似Runnable
}
);
以下方法用于计算斐波那契数列:
NSString *result=[self fbAtiIndex:1000]; // result为计算结果
以下代码用于显示:
UITextView *textview=[UITextView new];
textview.text=result; //result为显示结果
组合起来为:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// 处理耗时操作的代码块...
int i=0;
UITextView *textview=[UITextView new];
while(true){
NSString *result=[self fbAtiIndex:i];
//设置结果
[textview setText:result];
i++;
sleep(1);
}
});
很开心执行,但是数据并没有显示,而且崩溃了,得出如下错误日志:
三 异同之处
1.广播
Android&iOS都有广播这个功能,
iOS注册广播:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loginComplete) name:@"loginComplete" object:nil];
同样需要解注册:
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"loginComplete" object:nil];
2.listview复用
Android:
在RecyclerView里面,每个Item的View对象是复用的,当上拉下拉时,来回都是那几个View对象,但View对象上显示的数据在改变。所以,处理不好可能出现显示数据错乱问题。这个过程对开发者无感的,自动完成
iOS:
在iOS中listview每一行对应的对象是UITableViewCell,类似Android的view.
//查询是否有可以复用的 UITableViewCell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: FirstLevelCell];
if (cell == nil) {
//实例化 UITableViewCell,当划出屏膜时,会回收
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: FirstLevelCell];
}
3.数据库SQLite
iOS&Android的默认数据库都是SQLite,使用方法基本一样,区别只是Java和object的语法差异。
NSString *SQL = [NSString stringWithFormat:@"UPDATE 't_User' SET icon='%@' WHERE name = '%@'",@"Icon.png",@"name_6"];
if ([[SQLiteManager shareInstance] execSQL:SQL]) {
NSLog(@"对应数据修改成功");
}
4.依赖管理
为了利用别人优秀的代码,依赖管理是必不可少的,在Android上我们使用gradle,而iOS用pod
pod的依赖文件例子如下:
语法类似gradle, pod对于api,紧跟着依赖名字,版本号。
5. 图片库
对于很多应用来说,都会从网络加载显示图片,而图片相对来说消耗流量比较大,因此都会有缓存啊什么的,在这个特性上Android&iOS都是类似的。
如iOS可以用SDWebImage,缓存特性配置
Android的ImageLoader,设置缓存特性
基本用法也差不多,区别也就语法吧。
6.object-c的block,java的匿名内部类
在编程过程中,有时会写一段代码块,作为一个任务,叫给子线程执行或者稍后触发某个条件时执行,object-c和Java都有这个功能
在object-c上,这个成为block,代码块
例子:
printBlock = ^{
NSLog(@"print:%@", str);
};
这个block,即printBlock对象,可以传来传去,执行的时候:
printBlock()
在java上,可以利用匿名内部类,(其他什么类都行~~)
例子:
Runnable printRunnable=new Runnable() {
@Override
public void run() {
System.out.print("Runnable");
}
};
7.垃圾自动回收
object-c:
采用引用计数,假如有对象A,有个属性count, 表示引用计数, 刚实例化出来,赋值给B实例某字段,那么count为1,假如又赋值给C实例某字段,那么count再加一,只要count不为0,就表示A实例还在使用,不回收,假如B和C实例清空了指向A实例的字段,count减到0,就可以回收了。
采用引用计数的垃圾回收无法处理循环引用问题,如A和B实例互相引用,它们的count都不为0,但除此之外没有任何对象指向它们,这时,它们无法回收,这两个对象就在空中飘和飘,不过,它们是一对,也不会孤单了.........
那么object-c采用什么方法处理这个问题呢?
我没有研究。。。
java:图遍历
图遍历肯定保证不会出现某个对象无法回收的问题,原理是,把某些对象作为根节点,开始遍历,能遍历到的就是在用的,其他就当垃圾了,清掉它们就对了,那么那些对象是作为根节点呢?
Java虚拟机将以下对象定义为 GC Roots (根节点):
Java虚拟机栈中引用的对象:比如方法里面定义这种局部变量 User user= new User();
静态属性引用的对象:比如 private static User user = new User();
常量引用的对象:比如 private static final User user = new User();
本地方法栈中引用的对象
8.布局编写
Android的布局编写相对简单,基本是写xml文件,自动加载解析文件,自动测量,布局每个view的位置,即其XY坐标和宽高都是自动确定的,
iOS呢?
。。。。。。
iOS基本采用纯代码编写view:(手动设置XY坐标,宽高)
假如要隐藏界面中间一个view,安卓只需一句
View.setVisibility(View.GONE);
而iOS呢?
需要手动把下半部分的所有View的Y值往上移。。
9.前端交互
Android:
对于js调用Java,Android提供了WebView.addJavascriptInterface()来进行通讯,非常简单。在android:targetSdkVersion数值为17以下的设备中,js可以调用任何Java的public方法,引起了安全问题,因此在新版本中,只有含有@JavascriptInterface注解的方法才可以被js调用。
除此之外,js调用Java还有其他非常规的方法。其实,只有js能利用某种渠道传递信息给Java,给可以做很多事,包括方法调用
例如自定义通讯格式:
fun:a:b
表明这是一个方法调用,调用对象a的b方法这样子。
第一个是利用WebViewClient的shouldOverrideUrlLoading回调,采用自定义通讯格式,通过判断url来调用Java方法。
第二个是利用window.alert (前端调用); 拿出前端传过来的信息区解析自定义格式,去调用Java方法。
第三个是 console.log (前端调用)? 我忘记了,就是一个前端打日志的方法,Java拦截解析信息。执行想要的逻辑。
iOS:
iOS提供了JavaScriptCore框架,类似Android的WebView.addJavascriptInterface()
Android注册一个名称为xiuxingzheapp的对象给js调用如下
mWebViewController.addJavascriptInterface(siYuanJsCallJava, "xiuxingzheapp");
JavaScriptCore差不多,同样注册一个名称为xiuxingzheapp
JSProtocolObj=[QiuYuanJSProtocolObj new];
//与安卓一样 都是xiuxingzheapp 名字
jsContext[@"xiuxingzheapp"] = JSProtocolObj;
对于js来说,同样的对象名,使用方式也是一样。
iOS同样也可以使用其它自定义通讯格式进行js调原生代码,利用window.alert 等。
10.页面数据传递
Android:
Activity,Fragment之间传递数据,一般来说,都是通过Bundle把数据序列化传给另一页面。
Bundle args = new Bundle();
args.putSerializable(ARG_PARAM_FRAGMENT_TYPE, mFragmentType);
fragment.setArguments(args);
iOS:
很简单,给页面实例赋值就可以了(xxViewController就是页面,类似Android的xxActivity)
//创建页面实例
QiuYuanMMCWKViewController *tempController = [QiuYuanMMCWKViewController showWithContro:self withUrlStr:urlString withTitle:@"我的福单"];
// 给页面实例赋值
tempController.navItemColor = [UIColor ccColorWithHex:0xaaaaaa];
11 命名空间
Java:
在Java里,多个代码可以组织管理在一起,例如自己可以采用命名空间:com.hello ,在里面写一个类A.java,发布给别人用时,只需在源代码开头加上:
import com.hello.A
就可以使用
假如另一个人同样起一个类名A.java,但是他的命名空间为:com.love ,就不会于自己的类A.java冲突,使用时
用完全限定名就好,如:
com.hello.A.xx();
com. love .A xx();
object-c:
object-c就比较奇葩了,没有命名空间,Java引入一个类是这样:
import android.content.Context;
object-c是这样:
#import "Constant.h"
它没有Java的命名空间那样的前缀如com.hello这些,直接按照文件名字引入文件,对于Java来说,可以同时存在多个A.java,但是object-c就不能同时存在多个A.h了,那object-c是怎么做的呢?
看个例子:
嗯~~~
就是在每个类名上加统一的前缀,来表示这个代码是那个模块的,很不优雅。。。。。。
9.上传
安卓:审核简单,快速
ios:非常慢,要求严格 (ipv6,虚拟支付要走苹果支付),后台非常多bug,数据各种错乱。
10 兼容性
苹果的兼容性就是没有兼容性,假如你升级了调试设备,那就不能调试了,要升级xcode,然后xcode告诉你要升级我必须先升级系统,连环升级。