1.對(duì)于cell而言,使用自動(dòng)布局和高度緩存哪種方式比較好,為什么
1.使用自動(dòng)布局會(huì)根據(jù)給出的約束,在運(yùn)行時(shí)對(duì)約束的描述信息進(jìn)行求解,最終使用frame來(lái)繪制視圖
2.iOS應(yīng)用的視圖要保持60fps的刷新幀率,那么必須在16.67ms之內(nèi)完成包括布局,繪制以及渲染等操作,由于自動(dòng)布局本身的計(jì)算量非常巨大,而且還有設(shè)置frame的過(guò)程消耗時(shí)間,那么當(dāng)頁(yè)面上的視圖非常多的時(shí)候,自動(dòng)布局就無(wú)法達(dá)到絕對(duì)流暢的要求
3.由于自動(dòng)布局的實(shí)現(xiàn)原理導(dǎo)致他的時(shí)間復(fù)雜度為多項(xiàng)式時(shí)間褥民,其性能損耗是僅使用frame的十幾倍,所以,在處理龐大的UI界面時(shí)表現(xiàn)差強(qiáng)人意
4.強(qiáng)制視圖在主線(xiàn)程上布局
2.UIWebView和WKWebView的區(qū)別
1.對(duì)于UIWebView而言 js的alert是可以直接執(zhí)行的,而在WKWebView上,js彈窗是彈不出來(lái)的,需要通過(guò)WKUIDelegate協(xié)議接收彈窗事件丈挟,然后通過(guò)iOS原生彈窗runJavaScriptAlertPanel
2.UIWebView接受一個(gè)js字符串參數(shù) 返回一個(gè)字符串,同步執(zhí)行
WKWebView接受一個(gè)js字符串參數(shù) 返回一個(gè)ID類(lèi)型參數(shù) 異步執(zhí)行
3.WKWebView js調(diào)用OC的方法使用交互管理WKUserContentController 注冊(cè)方法 在didReceiveScriptMessage里面具體實(shí)現(xiàn)
4. WKWebView使用WKWebViewConfiguration可以設(shè)置一些屬性 輕松的對(duì)載入的網(wǎng)頁(yè)進(jìn)行一些簡(jiǎn)單高效的配置
5.WKWebView的占用內(nèi)存更小,加載速度比UIWebView更快
6.WKWebView的cookie問(wèn)題很難處理 與js的交互不夠靈活
//創(chuàng)建網(wǎng)頁(yè)配置對(duì)象
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
// 創(chuàng)建設(shè)置對(duì)象
WKPreferences *preference = [[WKPreferences alloc]init];
//最小字體大小 當(dāng)將javaScriptEnabled屬性設(shè)置為NO時(shí)果录,可以看到明顯的效果
preference.minimumFontSize = 0;
//設(shè)置是否支持javaScript 默認(rèn)是支持的
preference.javaScriptEnabled = YES;
// 在iOS上默認(rèn)為NO,表示是否允許不經(jīng)過(guò)用戶(hù)交互由javaScript自動(dòng)打開(kāi)窗口
preference.javaScriptCanOpenWindowsAutomatically = YES;
config.preferences = preference;
// 是使用H5的視頻播放器在線(xiàn)播放, 還是使用原生播放器全屏播放
config.allowsInlineMediaPlayback = YES;
//設(shè)置視頻是否需要用戶(hù)手動(dòng)播放 設(shè)置為NO則會(huì)允許自動(dòng)播放
config.requiresUserActionForMediaPlayback = YES;
//設(shè)置是否允許畫(huà)中畫(huà)技術(shù) 在特定設(shè)備上有效
config.allowsPictureInPictureMediaPlayback = YES;
//設(shè)置請(qǐng)求的User-Agent信息中應(yīng)用程序名稱(chēng) iOS9后可用
config.applicationNameForUserAgent = @"ChinaDailyForiPad";
3.使用WKWebView進(jìn)行和js的交互
1.oc調(diào)用js方法
使用evaluateJavaScript
//changeColor()是JS方法名掷邦,completionHandler是異步回調(diào)block
NSString *jsString = [NSString stringWithFormat:@"changeColor('%@')", @"Js參數(shù)"];
[_webView evaluateJavaScript:jsString completionHandler:^(id _Nullable data, NSError * _Nullable error) {
NSLog(@"改變HTML的背景色");
}];
1.js調(diào)用oc方法
//這個(gè)類(lèi)主要用來(lái)做native與JavaScript的交互管理
WKUserContentController * wkUController = [[WKUserContentController alloc] init];
//注冊(cè)一個(gè)name為jsToOcNoPrams的js方法,設(shè)置處理接收J(rèn)S方法的代理
[wkUController addScriptMessageHandler:self name:@"jsToOcNoPrams"];
[wkUController addScriptMessageHandler:self name:@"jsToOcWithPrams"];
config.userContentController = wkUController;
注意:遵守WKScriptMessageHandler協(xié)議,代理是由WKUserContentControl設(shè)置
//通過(guò)接收J(rèn)S傳出消息的name進(jìn)行捕捉的回調(diào)方法 js調(diào)OC
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
NSLog(@"name:%@\\n body:%@\\n frameInfo:%@\\n",message.name,message.body,message.frameInfo);
}
WKWebView的使用
WKWebView和UIWebView的區(qū)別
4.WKWebview Cookie
WKWebview Cookie 如何存儲(chǔ)的
session級(jí)別的cookie
session級(jí)別的cookie是保存在WKProcessPool里的,每個(gè)WKWebView都可以關(guān)聯(lián)一個(gè)WKProcessPool,如果需要在整個(gè)App生命周期內(nèi)訪(fǎng)問(wèn)h5保留h5里的登錄狀態(tài),可以將使用WKProcessPool的單列來(lái)共享登錄狀態(tài)
WKProcessPool是沒(méi)有屬性和方法的對(duì)象,唯一的作用就是標(biāo)識(shí)是不是需要新的session級(jí)別的管理對(duì)象磷支,一個(gè)實(shí)例代表一個(gè)對(duì)象
未過(guò)期的cookie
有有效期的 cookie 被持久化存儲(chǔ)在 NSLibraryDirectory
目錄下的 Cookies/
文件夾棺棵。
在Cookie目錄下兩個(gè)文件比較重要
Cookie.binarycookies
<appid>.binarycookies
兩者的區(qū)別是<appid>.binarycookies是NSHTTPCookieStorag文件對(duì)象
Cookie.binarycookies是WKWebView實(shí)例化對(duì)象
這就是WKWebview 和 NSHTTPCookieStorage 的原因——因?yàn)楸槐4嬖诓煌奈募?dāng)中
WKWebview Cookie 如何工作的
1.當(dāng)webView loadRequest或者302或者webView加載完畢,觸發(fā)了ajax請(qǐng)求時(shí),WKWebView所需的Cookie會(huì)去Cookie.binarycookies里讀取本域名下的Cookie,加上WKProcessPool持有的Cookie一起作為request頭里的Cookie數(shù)據(jù)
如何傳遞cookie
let cooki = "document.cookie = '這里是你需要的cookie值'
let userContentController = WKUserContentController()
let userScript = WKUserScript(source: cooki, injectionTime:WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)
userContentController.addUserScript(userScript)
let config = WKWebViewConfiguration()
config.userContentController = userContentController
var url = URLRequest(url: URL(string: sqlUrl)!, cachePolicy: URLRequest.CachePolicy.useProtocolCachePolicy, timeoutInterval: 20)
webV = WKWebView(frame: UIScreen.main.bounds, configuration: config)
第一次拿到cookie
NSString *cookieStr = [self setupCookie]; //保持APP登錄狀態(tài)同步到web
WKUserScript *cookieScript = [[WKUserScript alloc] initWithSource:cookieStr injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
[configuration.userContentController addUserScript:cookieScript];
- (NSString *)setupCookie
{ NSMutableDictionary *cookieDic = [NSMutableDictionary dictionary];
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSString *currentHostUrl = [IQHAPIService apiBaseUrlString];;
NSString *hostDomin = [currentHostUrl stringByReplacingOccurrencesOfString:@"http://mobile" withString:@""];
for (NSHTTPCookie *cookie in [cookieJar cookies]) {
if ([hostDomin isEqualToString:cookie.domain]) {
[cookieDic setObject:cookie.value forKey:cookie.name];
}
}
NSString *sessionType = @"APPSESSIONID";
NSString *cookieStr = @"";
for (NSString *key in cookieDic) {
if([key isEqualToString:@"SESSION"]){
NSString *appendString = [NSString stringWithFormat:@"'%@=%@;path=/';",sessionType,[cookieDic valueForKey:key]];
cookieStr = [NSString stringWithFormat:@"%@document.cookie=%@",cookieStr,appendString];
}
}
return cookieStr;
}
5.遠(yuǎn)程推送原理
Provider是自己程序的后臺(tái)服務(wù)器,APNS是Apple Push Notification Server的縮寫(xiě),蘋(píng)果推送服務(wù)器
分為三個(gè)階段
1.應(yīng)用程序的服務(wù)端把要發(fā)送的信息,目的iPhone的標(biāo)識(shí)打包,發(fā)送給APNS
2.APNS在自身的已注冊(cè)Push服務(wù)的iPhone列表中,查找相應(yīng)標(biāo)識(shí)的iPhone,并把消息發(fā)送到iPhone
3.iPhone把發(fā)來(lái)的消息傳遞給相應(yīng)的應(yīng)用程序,并且按照設(shè)定彈出Push通知
1.應(yīng)用程序注冊(cè)APNS消息推送
2.iOS從APNS獲取deviceToken 應(yīng)用程序接受deviceToken
3.應(yīng)用程序?qū)evice token發(fā)送給程序的PUSH服務(wù)器程序
4.服務(wù)端程序向APNS服務(wù)發(fā)送消息
5.APNS服務(wù)獎(jiǎng)消息發(fā)送給iPhone應(yīng)用程序
由于直接生成的證書(shū)windows系統(tǒng)是不識(shí)別的楼咳,所以我們需要生成一個(gè)后綴為pem的帶證書(shū)帶秘鑰的文件
1.把.cer的ssl證書(shū)轉(zhuǎn)換為.pem文件
openssl x509 -in aps_development.cer -inform der -out PushChatCert.pem
2.把私鑰Push.p12證書(shū)轉(zhuǎn)換為.pem文件
openssl pkcs12 -nocerts -out PushChatKey.pem -in Push.p12
3.把生成的兩個(gè)pem文件再生成一個(gè)pem文件 把證書(shū)和私鑰整合到一個(gè)文件里
cat PushChatCert.pem PushChatKey.pem > ck.pem
4.測(cè)試證書(shū)是否工作
telnet gateway.sandbox.push.apple.com 2195
5.使用SSL證書(shū)和私鑰來(lái)設(shè)置一個(gè)安全的鏈接去鏈接蘋(píng)果服務(wù)器
openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushChatCert.pem -key PushChatKey.pem
6.建立推送
在AppDelegate里didFinishLaunchingWithOptions函數(shù)里寫(xiě)
(BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//推送的形式:標(biāo)記,聲音烛恤,提示
[[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeBadge |UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert];
return YES;
}(void)application:(UIApplication *)applicationdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken {
NSLog(@"regisger success:%@",pToken);
//注冊(cè)成功母怜,將deviceToken保存到應(yīng)用服務(wù)器數(shù)據(jù)庫(kù)中
}(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
// 處理推送消息
NSLog(@"userinfo:%@",userInfo);NSLog(@"收到推送消息:%@",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]);
}(void)application:(UIApplication *)applicationdidFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"Registfail%@",error);
}