1: objective-c与javascript交互
用 Objective-C 取得与设定 JavaScript 对象
1 | js: |
- JS 虽然是 OO,但是并没有 class,所以将 JS 对象传到 Obj C 程序里头,除了基本字串会转换成 NSString、基本数字会转成 NSNumber,像是 Array 等其他对象,在 Objective-C 中,都是 WebScriptObject 这个 Class。意思就是,JS 的 Array 不会帮你转换成 NSArray。
- 从 JS 里头传一个空对象给 Objective-C 程序,用的不是 Objective-C 里头原本表示「没有东西」的方式,像是 NULL、nil、NSNull 等,而是专属 WebKit 使用的 WebUndefined。
用 Objective C 调用 JavaScript function
js调用oc
1
2
3
4
5oc:
[[webView windowScriptObject] evaluateWebScript:@"function x(x) { return x + 1;}"];
js:
window.x(1);oc调用js
1
2
3
4
5oc:
[[webView windowScriptObject] evaluateWebScript:[NSString stringWithFormat:@"showPromoAd('%@','%@');",self.word, computerSerialNumber()]];
js:
function showPromoAd(word, id){};
DOM
- WebKit 里头,所有的 DOM 对象都继承自 DOMObject,DOMObject 又继承自 WebScriptObject,所以我们在取得了某个 DOM 对象之后,也可以从 Objective-C 程序中,要求这个 DOM 对象执行 JS 程序
1
2
3
4
5
6js:
document.querySelector('#s').focus();
oc:
DOMDocument *document = [[webView mainFrame] DOMDocument];
[[document querySelector:@"#s"] callWebScriptMethod:@"focus"withArguments:nil];
用 JavaScript 存取 Objective C 的 Value
要让网页中的 JS 程序可以调用 Objective-C 对象,方法是把某个 Objective-C 对象注册成 JS 中 window 对象的属性。之后,JS 便也可以调用这个对象的 method,也可以取得这个对象的各种 Value,只要是 KVC 可以取得的 Value,像是 NSString、NSNumber、NSDate、NSArray、NSDictionary、NSValue…等。JS 传 Array 到 Objective-C 时,还需要特别做些处理才能变成 NSArray,从 Obj C 传一个 NSArray 到 JS 时,会自动变成 JS Array。
首先我们要注意的是将 Objective-C 对象注册给 window 对象的时机,由于每次重新载入网页,window 对象的内容都会有所变动-毕竟每个网页都会有不同的 JS 程序,所以,我们需要在适当的时机做这件事情。我们首先要指定 WebView 的 frame loading delegate(用 setFrameLoadDelegate:),并且实作 webView:didClearWindowObject:forFrame:,WebView 只要更新了 windowScriptObject,就会调用这一段程序。
用 JavaScript 调用 Objective C method
- Objective-C 的语法沿袭自 SmallTalk,Objective-C 的 selector,与 JS 的 function 语法有相当的差异。WebKit 预设的实事是,如果我们要在 JS 调用 Objective-C selector,就是把所有的参数往后面摆,并且把所有的冒号改成底线,而原来 selector 如果有底线的话,又要另外处理。
2: jsbridge
OC端
引入依赖文件
1
2
3#import "WebViewJavascriptBridge.h"
...
@property WebViewJavascriptBridge* bridge;实例化一个对象
1
self.bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
OC端 注册一个方法+ 调用该方法的函数
1
2
3
4
5
6
7
8
9
10//供前端调用
[self.bridge registerHandler:@"OCTest" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"ObjC Echo called with: %@", data);
responseCallback(data);
}];
//主动推送给前端
[self.bridge callHandler:@"JsTest" data:nil responseCallback:^(id responseData) {
NSLog(@"ObjC received response: %@", responseData);
}];
JS端
1 | function setupWebViewJavascriptBridge(callback) { |
原理
- 分别在OC环境和javascript环境都保存一个bridge对象,里面维持着requestId,callbackId,以及每个id对应的具体实现。
- OC通过javascript环境的window.WebViewJavascriptBridge对象来找到具体的方法,然后执行。
- javascript通过改变iframe的src来出发webview的代理方法,从而实现把javascript消息发送给OC这个功能。
工作流
- JS 端加入 src 为 https://bridge_loaded 的 iframe
- Native 端检测到 Request,检测如果是 bridge_loaded 则通过当前的 WebView 组件注入 WebViewJavascriptBridge_JS 代码
- 注入代码成功之后会加入一个 messagingIframe,其 src 为 https://wvjb_queue_message
- 之后不论是 Native 端还是 JS 端都可以通过 registerHandler 方法注册一个两端约定好的 HandlerName 的处理,也都可以通过 callHandler 方法通过约定好的 HandlerName 调用另一端的处理(两端处理消息的实现逻辑对称)
3: ios本地缓存数据
直接写文件方式
- 可以存储的对象有NSString、NSArray、NSDictionary、NSData、NSNumber,数据全部存放在一个属性列表文件(*.plist文件)中。
NSUserDefaults
- 一般应用来存储应用设置信息,文件放在perference目录下。
归档操作(NSkeyedArchiver)
- 不同于前面两种,它可以把自定义对象存放在文件中。
coreData
- coreData是苹果官方iOS5之后推出的综合型数据库。
FMDB
- FMDB是iOS平台的SQLite数据库框架,FMDB以OC的方式封装了SQLite的C语言API,使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码。
4: 页面之间通信
- 属性传值
- 正向传值:page1–>page2
单例传值
1
2
3
4
5
6
7
8
9+(instancetype)sharedInstance{
static SharedInstance* _sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[SharedInstance alloc] init];
});
return _sharedInstance;
}NSUserDefaults
- 代理传值
- A:代理方(遵守协议、实现协议方法)
- B:委托方(制定持有协议,调用协议方法)
- C:中间通讯(delegate)
- block传值
通知传值–NSNotificationCenter
1
2
3
4
5
6
7
8
9//先监听
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateValue:) name:@"postValue" object:nil];
-(void)updateValue:(NSNotification*)not{
self.lable.text = not.userInfo[@"val"];
}
//发送广播
[[NSNotificationCenter defaultCenter] postNotificationName:@"postValue" object:nil userInfo:@{@"val":self.inputText}];
5: 文件操作
- NSFileHandle:文件内容的读取和写入
- NSFileManager:文件的删除和创建等
- 参考
6: 多线程
PThread(c框架,极少使用)
NSThread
三种创建方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14//方式一
NSThread *thread1 = [[NSThread alloc] initWithTarget: self selector:@selector(runThread1) object:nil];
[thread1 setName:@"name_thread1"]; //在selector方法里面获取当前线程[NSThread currentThread].name;
[thread1 setThreadPriority:0.5]; //优先级:0-1
[thread1 start];
//方式二
[NSThread detachNewThreadSelector:@selector(runThread1) toTarget:self withObject:nil];
//方式三
//回到主线程:performSelectorOnMainThread
[self performSelectorInBackground:@selector(runThread1) withObject:nil];
GCD
- 介绍:
- 类似前端的new worker(), 把耗时较长的任务交给子线程处理,主线程处理ui操作,任务完成worker.postMessage()告诉给主线程。
- 使用方式:
- 同步/异步、串行/并行
- dispath_get_global_queue & dispatch_get_main_queue
- dispatch_group_async
- dispatch_once
- dispatch_after
NSOperation
- 实现方式:
- NSInvocationOperation & NSBlockOperation(同步阻塞)
- 自定义类继承NSOperation
相关概念
- NSOperationQueue(异步队列)
- addOperation
- setMaxConcurrentOperationCount
- 状态
- ready、 cancelled、 executing、 finished、 asynchronous
- 依赖– addDependency
- NSOperationQueue(异步队列)
NSRunloop阻塞当然线程,让异步到达同步的效果。
dispatch_semaphore(信号量)
1 | - (NSInteger)methodSync { |
7: @property使用
使用方式
1
2
3
4
5//test.h
@property(nonatomic, readwrite, strong) NSString *test;
//test.m
@synthesize test;属性分类
- 原子性
- atomic (默认、原子性) 只有一个线程访问实例,atmoic是线程安全的。
- nonatomic (非原子性), 可以被多个线程访问,效率比atomic高,但是不能保证在多线程的安全性。
- 存取器控制
- readwrite (默认) 表示该属性同时拥有setter和getter。
- readonly 表示只有getter没有setter。
- 内存管理
- assign (默认) assign用于值类型,如int、float、double和NSInteger,CGFloat等表示单纯的复制。
- strong strong是在IOS引入ARC的时候引入的关键字,是retain的一个可选的替代。表示实例变量对传入的对象要有所有权关系,即强引用。strong跟retain的意思相同并产生相同的代码,但是语意上更好更能体现对象的关系。
- weak 在setter方法中,需要对传入的对象不进行引用计数加1的操作, 例如:IBOutlet、Delegate一般用的就是weak
- copy 与strong类似,但区别在于实例变量是对传入对象的副本拥有所有权,而非对象本身
- 原子性