Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
let UIWebView
as WKWebView
@taketo1024
2015/02/14
iOSオールスターズ勉強会
http://maths4pg.connpass.com
 本題
from: WWDC2014 Introducing the Modern WebKit API
from: WWDC2014 Introducing the Modern WebKit API
• iOS 2.0 からお馴染み
• JavaScript が Safari より遅い
from: WWDC2014 Introducing the Modern WebKit API
• iOS 2.0 からお馴染み
• JavaScript が Safari より遅い
• iOS 8.0 から導入
• Safari と同じ J...
WKWebViewを使いたい!
でもまだ iOS 7 を切るわけには行かない…
UIWebView (親: UIView) WKWebView (親: UIView)
var canGoBack: Bool { get }
var canGoForward: Bool { get }
var loading: Bool {...
UIWebView (親: UIView) WKWebView (親: UIView)
var canGoBack: Bool { get }
var canGoForward: Bool { get }
var loading: Bool {...
UIWebView (親: UIView) WKWebView (親: UIView)
var canGoBack: Bool { get }
var canGoForward: Bool { get }
var loading: Bool {...
UIWebView (親: UIView) WKWebView (親: UIView)
var canGoBack: Bool { get }
var canGoForward: Bool { get }
var loading: Bool {...
UIWebView (親: UIView) WKWebView (親: UIView)
var canGoBack: Bool { get }
var canGoForward: Bool { get }
var loading: Bool {...
class MyViewController: UIViewController {
var wkWebView: WKWebView?
var uiWebView: UIWebView?
override func viewDidLoad()...
class MyViewController: UIViewController {
var wkWebView: WKWebView?
var uiWebView: UIWebView?
override func viewDidLoad()...
class MyViewController: UIViewController {
var wkWebView: WKWebView?
var uiWebView: UIWebView?
override func viewDidLoad()...
class MyViewController: UIViewController {
var wkWebView: WKWebView?
var uiWebView: UIWebView?
override func viewDidLoad()...
これはよくない
バージョン分岐だらけのコードは危険
• コントローラやモデルの本来の役割が見えにくくなる。
• 古いコードが山積するといずれ誰も手に負えなくなる。
• 下位バージョンのサポートを切るときにも不必要なコー
ドが残りがち。
「OSの最新バージョンだけサポートしてればいいじゃん」
2015/02 時点でも iOS 8 のシェアは 72%。
100万 ユーザいれば 28万 は iOS 7 以前。
大きなユーザ数を持つサービスには重大な問題。
As measured by the App Store on February ...
どうするか?
「複雑性保存の法則」
タスクの複雑性はある点を超えて
減らすことはできない。
移動のみ可能である。
ラリー・テスラー

インタラクションデザイナ
ソフトウェアの設計についてもあてはまる!
下位互換対応は「隠 」せよ
• コントローラやモデルなどの上位層からはバージョ
ン分岐を意識しなくていいようにする。
• 混み入った分岐はどこかにまとめておいて、いつで
も簡単に切り離せるようにしておく。
• 広範囲で使用されるものでも、依存性...
2014-01-15 @ potatotips 3
Method Swizzling で iOS 7 コードを iOS 6 でも動かす
今回のお題
UIWebViewと
WKWebViewの

分岐処理を隠蔽せよ
方針1: ラッパーで包む
IF は WKWebView と共通にする
WKWebView
UIWebView
前処理
iOS 8 以上 iOS 7 以下
WKWebViewWrapper : UIView
class WKWebViewWrapper: UIView {
// どちらか一方はnil
var wkWebView: WKWebView?
var uiWebView: UIWebView?
override init(frame: CG...
class WKWebViewWrapper: UIView {
// どちらか一方はnil
var wkWebView: WKWebView?
var uiWebView: UIWebView?
override init(frame: CG...
class WKWebViewWrapper: UIView {
// どちらか一方はnil
var wkWebView: WKWebView?
var uiWebView: UIWebView?
override init(frame: CG...
class WKWebViewWrapper: UIView {
// どちらか一方はnil
var wkWebView: WKWebView?
var uiWebView: UIWebView?
override init(frame: CG...
目的は達成できているのだが、
全メソッドに分岐を入れるのが
あまりエレガントな感じしない。
方針2:
UIWebView に
WKWebView のフリをさせる
WKWebView UIWebView
iOS 8 以上 iOS 7 以下
WKWebView
UIWebView
iOS 8 以上 iOS 7 以下
WKWebView
UIWebView
WKWebView の IF
iOS 8 以上 iOS 7 以下
WKWebView
UIWebView
WKWebView の IF
Controller
iOS 8 以上 iOS 7 以下
外からは同じ型に見える
Obj-C 先輩の力を借りる
えっ
Why Obj-C ?
UIWebView WKWebView
var canGoBack: Bool { get }
var canGoForward: Bool { get }
var loading: Bool { get }
var c...
Why Obj-C ?
UIWebView WKWebView
var canGoBack: Bool { get }
var canGoForward: Bool { get }
var loading: Bool { get }
var c...
Obj-C の緩さに甘える
(どうせ隠 するんだしいいでしょ)
…許す
手順1: WKWebView の IF を Protocol として切り出す
// WKWebViewProtocol.swift
#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
@proto...
手順1: WKWebView の IF を Protocol として切り出す
// WKWebViewProtocol.swift
#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
@proto...
手順2: WKWebView の拡張で Protocol に適合
// WKWebView+ProtocolConformed.h
#import "WKWebViewProtocol.h"
@interface WKWebView(YSSWe...
手順2: WKWebView の拡張で Protocol に適合
// WKWebView+ProtocolConformed.h
#import "WKWebViewProtocol.h"
@interface WKWebView(YSSWe...
手順2: WKWebView の拡張で Protocol に適合
// WKWebView+ProtocolConformed.h
#import "WKWebViewProtocol.h"
@interface WKWebView(YSSWe...
手順3: 同様に UIWebView の拡張も作成
// UIWebView+WKProtocolConformed.h
#import "WKWebViewProtocol.h"
@interface UIWebView (WKProtoco...
手順3: 同様に UIWebView の拡張も作成
// UIWebView+WKProtocolConformed.h
#import "WKWebViewProtocol.h"
@interface UIWebView (WKProtoco...
UIWebView には足りないメソッドを実装する!
// UIWebView+WKProtocolConformed.m
#import "UIWebView+WKProtocolConformed.h"
@implementation UI...
UIWebView には足りないメソッドを実装する!
// UIWebView+WKProtocolConformed.m
#import "UIWebView+WKProtocolConformed.h"
@implementation UI...
準備はここまで
(Obj-Cのことはもう忘れてOK)
Controller で WKWebViewProtocol 型として webView を保持
// MyViewController.swift
import UIKit
import WebKit
class ViewController:...
Controller で WKWebViewProtocol 型として webView を保持
// MyViewController.swift
import UIKit
import WebKit
class ViewController:...
Controller で WKWebViewProtocol 型として webView を保持
// MyViewController.swift
import UIKit
import WebKit
class ViewController:...
Controller で WKWebViewProtocol 型として webView を保持
// MyViewController.swift
…(続き)
override func viewDidAppear(animated: Bool...
Controller で WKWebViewProtocol 型として webView を保持
// MyViewController.swift
…(続き)
override func viewDidAppear(animated: Bool...
DEMO
方針1:
Wrapper で包む
方針2:
UIWebViewをいじる
• 特別なことをしていないので安心。
• だいぶ裏技っぽい。
(戻り値型を捻じ曲げてる辺り特に)
• 全メソッドを実装して、それぞれ分岐
処理を書くのが面倒。
• UIWe...
いつか iOS 7 のサポートを切るとき、
UIWebView と気持ち良く別れられるように。
2014年12月 5日 Yahoo! JAPAN Tech Blog
let UIWebView as WKWebView
Thanks!
Blog: http://taketo1024.hateblo.jp
Twitter: @taketo1024
let UIWebView as WKWebView
let UIWebView as WKWebView
Upcoming SlideShare
Loading in …5
×

let UIWebView as WKWebView

28,352 views

Published on

iOS 8 で導入された WKWebView と、7 以前で使える UIWebView を、ソースを綺麗に保ったまま同居させる方法。

2015/02/14(土) 「iOSオールスターズ勉強会」にて発表。
http://eventdots.jp/event/311301

Published in: Software
  • DOWNLOAD FULL BOOKS INTO AVAILABLE FORMAT ......................................................................................................................... ......................................................................................................................... 1.DOWNLOAD FULL PDF EBOOK here { https://tinyurl.com/y8nn3gmc } ......................................................................................................................... 1.DOWNLOAD FULL EPUB Ebook here { https://tinyurl.com/y8nn3gmc } ......................................................................................................................... 1.DOWNLOAD FULL doc Ebook here { https://tinyurl.com/y8nn3gmc } ......................................................................................................................... 1.DOWNLOAD FULL PDF EBOOK here { https://tinyurl.com/y8nn3gmc } ......................................................................................................................... 1.DOWNLOAD FULL EPUB Ebook here { https://tinyurl.com/y8nn3gmc } ......................................................................................................................... 1.DOWNLOAD FULL doc Ebook here { https://tinyurl.com/y8nn3gmc } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

let UIWebView as WKWebView

  1. 1. let UIWebView as WKWebView @taketo1024 2015/02/14 iOSオールスターズ勉強会
  2. 2. http://maths4pg.connpass.com
  3. 3.  本題
  4. 4. from: WWDC2014 Introducing the Modern WebKit API
  5. 5. from: WWDC2014 Introducing the Modern WebKit API • iOS 2.0 からお馴染み • JavaScript が Safari より遅い
  6. 6. from: WWDC2014 Introducing the Modern WebKit API • iOS 2.0 からお馴染み • JavaScript が Safari より遅い • iOS 8.0 から導入 • Safari と同じ JavaScript エンジン! • ページ遷移ジェスチャーにも対応 • その他も何かと高性能で良い
  7. 7. WKWebViewを使いたい!
  8. 8. でもまだ iOS 7 を切るわけには行かない…
  9. 9. UIWebView (親: UIView) WKWebView (親: UIView) var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var title: String? { get } var URL: NSURL? { get } var estimatedProgress: Double { get } func loadRequest(request: NSURLRequest) 
 func reload() func stopLoading() func goBack() func goForward() func loadRequest(request: NSURLRequest) -> WKNavigation? func reload() -> WKNavigation? func stopLoading()
 func goBack() -> WKNavigation? func goForward() -> WKNavigation? func stringByEvaluatingJavaScriptFromString (script: String) -> String? func evaluateJavaScript(javaScriptString: String, completionHandler: ((AnyObject!, NSError!) -> Void)?) weak var delegate: UIWebViewDelegate? weak var navigationDelegate: WKNavigationDelegate?
 weak var UIDelegate: WKUIDelegate? インターフェースは似ているが互換性はない
  10. 10. UIWebView (親: UIView) WKWebView (親: UIView) var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var title: String? { get } var URL: NSURL? { get } var estimatedProgress: Double { get } func loadRequest(request: NSURLRequest) 
 func reload() func stopLoading() func goBack() func goForward() func loadRequest(request: NSURLRequest) -> WKNavigation? func reload() -> WKNavigation? func stopLoading()
 func goBack() -> WKNavigation? func goForward() -> WKNavigation? func stringByEvaluatingJavaScriptFromString (script: String) -> String? func evaluateJavaScript(javaScriptString: String, completionHandler: ((AnyObject!, NSError!) -> Void)?) weak var delegate: UIWebViewDelegate? weak var navigationDelegate: WKNavigationDelegate?
 weak var UIDelegate: WKUIDelegate? インターフェースは似ているが互換性はない WKWebView にしかないプロパティ
  11. 11. UIWebView (親: UIView) WKWebView (親: UIView) var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var title: String? { get } var URL: NSURL? { get } var estimatedProgress: Double { get } func loadRequest(request: NSURLRequest) 
 func reload() func stopLoading() func goBack() func goForward() func loadRequest(request: NSURLRequest) -> WKNavigation? func reload() -> WKNavigation? func stopLoading()
 func goBack() -> WKNavigation? func goForward() -> WKNavigation? func stringByEvaluatingJavaScriptFromString (script: String) -> String? func evaluateJavaScript(javaScriptString: String, completionHandler: ((AnyObject!, NSError!) -> Void)?) weak var delegate: UIWebViewDelegate? weak var navigationDelegate: WKNavigationDelegate?
 weak var UIDelegate: WKUIDelegate? インターフェースは似ているが互換性はない load系 は WKNavigation? 型の戻り値がある
  12. 12. UIWebView (親: UIView) WKWebView (親: UIView) var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var title: String? { get } var URL: NSURL? { get } var estimatedProgress: Double { get } func loadRequest(request: NSURLRequest) 
 func reload() func stopLoading() func goBack() func goForward() func loadRequest(request: NSURLRequest) -> WKNavigation? func reload() -> WKNavigation? func stopLoading()
 func goBack() -> WKNavigation? func goForward() -> WKNavigation? func stringByEvaluatingJavaScriptFromString (script: String) -> String? func evaluateJavaScript(javaScriptString: String, completionHandler: ((AnyObject!, NSError!) -> Void)?) weak var delegate: UIWebViewDelegate? weak var navigationDelegate: WKNavigationDelegate?
 weak var UIDelegate: WKUIDelegate? インターフェースは似ているが互換性はない JavaScript はコールバック形式
  13. 13. UIWebView (親: UIView) WKWebView (親: UIView) var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var title: String? { get } var URL: NSURL? { get } var estimatedProgress: Double { get } func loadRequest(request: NSURLRequest) 
 func reload() func stopLoading() func goBack() func goForward() func loadRequest(request: NSURLRequest) -> WKNavigation? func reload() -> WKNavigation? func stopLoading()
 func goBack() -> WKNavigation? func goForward() -> WKNavigation? func stringByEvaluatingJavaScriptFromString (script: String) -> String? func evaluateJavaScript(javaScriptString: String, completionHandler: ((AnyObject!, NSError!) -> Void)?) weak var delegate: UIWebViewDelegate? weak var navigationDelegate: WKNavigationDelegate?
 weak var UIDelegate: WKUIDelegate? インターフェースは似ているが互換性はない delegateが2種類ある(IFもだいぶ違う)
  14. 14. class MyViewController: UIViewController { var wkWebView: WKWebView? var uiWebView: UIWebView? override func viewDidLoad() { super.viewDidLoad() if NSClassFromString("WKWebView") != nil { wkWebView = WKWebView(frame: ) self.view.addSubview(wkWebView!) } else { uiWebView = UIWebView(frame: ) self.view.addSubview(uiWebView!) } } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let URL = NSURL(string: "http://yahoo.co.jp") let req = NSURLRequest(URL: URL!) if(wkWebView != nil) { wkWebView!.loadRequest(req) } else { uiWebView!.loadRequest(req) } } ナイーブな下位互換対応をすると…
  15. 15. class MyViewController: UIViewController { var wkWebView: WKWebView? var uiWebView: UIWebView? override func viewDidLoad() { super.viewDidLoad() if NSClassFromString("WKWebView") != nil { wkWebView = WKWebView(frame: ) self.view.addSubview(wkWebView!) } else { uiWebView = UIWebView(frame: ) self.view.addSubview(uiWebView!) } } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let URL = NSURL(string: "http://yahoo.co.jp") let req = NSURLRequest(URL: URL!) if(wkWebView != nil) { wkWebView!.loadRequest(req) } else { uiWebView!.loadRequest(req) } } ナイーブな下位互換対応をすると… UIWebView / WKWebView の両方を変数で宣言
  16. 16. class MyViewController: UIViewController { var wkWebView: WKWebView? var uiWebView: UIWebView? override func viewDidLoad() { super.viewDidLoad() if NSClassFromString("WKWebView") != nil { wkWebView = WKWebView(frame: ) self.view.addSubview(wkWebView!) } else { uiWebView = UIWebView(frame: ) self.view.addSubview(uiWebView!) } } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let URL = NSURL(string: "http://yahoo.co.jp") let req = NSURLRequest(URL: URL!) if(wkWebView != nil) { wkWebView!.loadRequest(req) } else { uiWebView!.loadRequest(req) } } ナイーブな下位互換対応をすると… 対応/非対応に応じて一方にインスタンスを入れる
  17. 17. class MyViewController: UIViewController { var wkWebView: WKWebView? var uiWebView: UIWebView? override func viewDidLoad() { super.viewDidLoad() if NSClassFromString("WKWebView") != nil { wkWebView = WKWebView(frame: ) self.view.addSubview(wkWebView!) } else { uiWebView = UIWebView(frame: ) self.view.addSubview(uiWebView!) } } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let URL = NSURL(string: "http://yahoo.co.jp") let req = NSURLRequest(URL: URL!) if(wkWebView != nil) { wkWebView!.loadRequest(req) } else { uiWebView!.loadRequest(req) } } ナイーブな下位互換対応をすると… そして毎回分岐して同じ処理を2度書くことに…
  18. 18. これはよくない
  19. 19. バージョン分岐だらけのコードは危険 • コントローラやモデルの本来の役割が見えにくくなる。 • 古いコードが山積するといずれ誰も手に負えなくなる。 • 下位バージョンのサポートを切るときにも不必要なコー ドが残りがち。
  20. 20. 「OSの最新バージョンだけサポートしてればいいじゃん」
  21. 21. 2015/02 時点でも iOS 8 のシェアは 72%。 100万 ユーザいれば 28万 は iOS 7 以前。 大きなユーザ数を持つサービスには重大な問題。 As measured by the App Store on February 2, 2015.
  22. 22. どうするか?
  23. 23. 「複雑性保存の法則」 タスクの複雑性はある点を超えて 減らすことはできない。 移動のみ可能である。 ラリー・テスラー
 インタラクションデザイナ ソフトウェアの設計についてもあてはまる!
  24. 24. 下位互換対応は「隠 」せよ • コントローラやモデルなどの上位層からはバージョ ン分岐を意識しなくていいようにする。 • 混み入った分岐はどこかにまとめておいて、いつで も簡単に切り離せるようにしておく。 • 広範囲で使用されるものでも、依存性は最小限に。
  25. 25. 2014-01-15 @ potatotips 3 Method Swizzling で iOS 7 コードを iOS 6 でも動かす
  26. 26. 今回のお題 UIWebViewと WKWebViewの
 分岐処理を隠蔽せよ
  27. 27. 方針1: ラッパーで包む IF は WKWebView と共通にする WKWebView UIWebView 前処理 iOS 8 以上 iOS 7 以下 WKWebViewWrapper : UIView
  28. 28. class WKWebViewWrapper: UIView { // どちらか一方はnil var wkWebView: WKWebView? var uiWebView: UIWebView? override init(frame: CGRect) { super.init(frame: frame) if NSClassFromString("WKWebView") != nil { wkWebView = WKWebView(frame: self.bounds) self.addSubview(wkWebView!) } else { uiWebView = UIWebView(frame: self.bounds) self.addSubview(uiWebView!) } } func loadRequest(request: NSURLRequest) -> WKNavigation? { if(wkWebView != nil) { return wkWebView!.loadRequest(request); } else { uiWebView!.loadRequest(request) return nil } } 内部の実装イメージ
  29. 29. class WKWebViewWrapper: UIView { // どちらか一方はnil var wkWebView: WKWebView? var uiWebView: UIWebView? override init(frame: CGRect) { super.init(frame: frame) if NSClassFromString("WKWebView") != nil { wkWebView = WKWebView(frame: self.bounds) self.addSubview(wkWebView!) } else { uiWebView = UIWebView(frame: self.bounds) self.addSubview(uiWebView!) } } func loadRequest(request: NSURLRequest) -> WKNavigation? { if(wkWebView != nil) { return wkWebView!.loadRequest(request); } else { uiWebView!.loadRequest(request) return nil } } 内部の実装イメージ UIWebView / WKWebView の両方を変数で宣言
  30. 30. class WKWebViewWrapper: UIView { // どちらか一方はnil var wkWebView: WKWebView? var uiWebView: UIWebView? override init(frame: CGRect) { super.init(frame: frame) if NSClassFromString("WKWebView") != nil { wkWebView = WKWebView(frame: self.bounds) self.addSubview(wkWebView!) } else { uiWebView = UIWebView(frame: self.bounds) self.addSubview(uiWebView!) } } func loadRequest(request: NSURLRequest) -> WKNavigation? { if(wkWebView != nil) { return wkWebView!.loadRequest(request); } else { uiWebView!.loadRequest(request) return nil } } 内部の実装イメージ 対応/非対応に応じて一方にインスタンスを入れる
  31. 31. class WKWebViewWrapper: UIView { // どちらか一方はnil var wkWebView: WKWebView? var uiWebView: UIWebView? override init(frame: CGRect) { super.init(frame: frame) if NSClassFromString("WKWebView") != nil { wkWebView = WKWebView(frame: self.bounds) self.addSubview(wkWebView!) } else { uiWebView = UIWebView(frame: self.bounds) self.addSubview(uiWebView!) } } func loadRequest(request: NSURLRequest) -> WKNavigation? { if(wkWebView != nil) { return wkWebView!.loadRequest(request); } else { uiWebView!.loadRequest(request) return nil } } 内部の実装イメージ すべてのメソッドで分岐処理
  32. 32. 目的は達成できているのだが、 全メソッドに分岐を入れるのが あまりエレガントな感じしない。
  33. 33. 方針2: UIWebView に WKWebView のフリをさせる
  34. 34. WKWebView UIWebView iOS 8 以上 iOS 7 以下
  35. 35. WKWebView UIWebView iOS 8 以上 iOS 7 以下
  36. 36. WKWebView UIWebView WKWebView の IF iOS 8 以上 iOS 7 以下
  37. 37. WKWebView UIWebView WKWebView の IF Controller iOS 8 以上 iOS 7 以下 外からは同じ型に見える
  38. 38. Obj-C 先輩の力を借りる えっ
  39. 39. Why Obj-C ? UIWebView WKWebView var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var title: String? { get } var URL: NSURL? { get } var estimatedProgress: Double { get } func loadRequest(request: NSURLRequest) 
 func reload() func stopLoading() func goBack() func goForward() func loadRequest(request: NSURLRequest) -> WKNavigation? func reload() -> WKNavigation? func stopLoading()
 func goBack() -> WKNavigation? func goForward() -> WKNavigation? func stringByEvaluatingJavaScriptFromString (script: String) -> String? func evaluateJavaScript(javaScriptString: String, completionHandler: ((AnyObject!, NSError!) -> Void)?) weak var delegate: UIWebViewDelegate? weak var navigationDelegate: WKNavigationDelegate?
 weak var UIDelegate: WKUIDelegate?
  40. 40. Why Obj-C ? UIWebView WKWebView var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var canGoBack: Bool { get } var canGoForward: Bool { get } var loading: Bool { get } var title: String? { get } var URL: NSURL? { get } var estimatedProgress: Double { get } func loadRequest(request: NSURLRequest) 
 func reload() func stopLoading() func goBack() func goForward() func loadRequest(request: NSURLRequest) -> WKNavigation? func reload() -> WKNavigation? func stopLoading()
 func goBack() -> WKNavigation? func goForward() -> WKNavigation? func stringByEvaluatingJavaScriptFromString (script: String) -> String? func evaluateJavaScript(javaScriptString: String, completionHandler: ((AnyObject!, NSError!) -> Void)?) weak var delegate: UIWebViewDelegate? weak var navigationDelegate: WKNavigationDelegate?
 weak var UIDelegate: WKUIDelegate? Swift はココの戻り値の型の違いを区別してしまう! (かなり頑張ったけど無理でした笑)
  41. 41. Obj-C の緩さに甘える (どうせ隠 するんだしいいでしょ) …許す
  42. 42. 手順1: WKWebView の IF を Protocol として切り出す // WKWebViewProtocol.swift #import <UIKit/UIKit.h> #import <WebKit/WebKit.h> @protocol WKWebViewProtocol <NSObject> @property (nonatomic, readonly, getter=canGoBack) BOOL canGoBack; @property (nonatomic, readonly, getter=canGoForward) BOOL canGoForward; @property (nonatomic, readonly, getter=isLoading) BOOL loading; @property (nonatomic, readonly) NSURL *URL; @property (nonatomic, readonly, copy) NSString *title; - (void)loadRequest:(NSURLRequest *)request; - (void)reload; - (void)stopLoading; - (void)goBack; - (void)goForward; - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler; @end
  43. 43. 手順1: WKWebView の IF を Protocol として切り出す // WKWebViewProtocol.swift #import <UIKit/UIKit.h> #import <WebKit/WebKit.h> @protocol WKWebViewProtocol <NSObject> @property (nonatomic, readonly, getter=canGoBack) BOOL canGoBack; @property (nonatomic, readonly, getter=canGoForward) BOOL canGoForward; @property (nonatomic, readonly, getter=isLoading) BOOL loading; @property (nonatomic, readonly) NSURL *URL; @property (nonatomic, readonly, copy) NSString *title; - (void)loadRequest:(NSURLRequest *)request; - (void)reload; - (void)stopLoading; - (void)goBack; - (void)goForward; - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler; @end WKWebViewのヘッダファイルからコピペしてくる
  44. 44. 手順2: WKWebView の拡張で Protocol に適合 // WKWebView+ProtocolConformed.h #import "WKWebViewProtocol.h" @interface WKWebView(YSSWebViewProtocol) <WKWebViewProtocol> @end // WKWebView+ProtocolConformed.m #import "WKWebView+ProtocolConformed.h" @implementation WKWebView(YSSWebViewProtocol) @end
  45. 45. 手順2: WKWebView の拡張で Protocol に適合 // WKWebView+ProtocolConformed.h #import "WKWebViewProtocol.h" @interface WKWebView(YSSWebViewProtocol) <WKWebViewProtocol> @end // WKWebView+ProtocolConformed.m #import "WKWebView+ProtocolConformed.h" @implementation WKWebView(YSSWebViewProtocol) @end Protocol の適合を宣言
  46. 46. 手順2: WKWebView の拡張で Protocol に適合 // WKWebView+ProtocolConformed.h #import "WKWebViewProtocol.h" @interface WKWebView(YSSWebViewProtocol) <WKWebViewProtocol> @end // WKWebView+ProtocolConformed.m #import "WKWebView+ProtocolConformed.h" @implementation WKWebView(YSSWebViewProtocol) @end 元から実装されているので拡張は何もいらない!
  47. 47. 手順3: 同様に UIWebView の拡張も作成 // UIWebView+WKProtocolConformed.h #import "WKWebViewProtocol.h" @interface UIWebView (WKProtocolConformed) <WKWebViewProtocol> @end
  48. 48. 手順3: 同様に UIWebView の拡張も作成 // UIWebView+WKProtocolConformed.h #import "WKWebViewProtocol.h" @interface UIWebView (WKProtocolConformed) <WKWebViewProtocol> @end 同様に WKWebView の Protocol 適合を宣言
  49. 49. UIWebView には足りないメソッドを実装する! // UIWebView+WKProtocolConformed.m #import "UIWebView+WKProtocolConformed.h" @implementation UIWebView (WKProtocolConformed) - (NSURL *)URL { NSString *URLString = [self stringByEvaluatingJavaScriptFromString:@"document.URL"]; return [NSURL URLWithString:URLString]; } - (NSString *)title { return [self stringByEvaluatingJavaScriptFromString:@"document.title"]; } - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler { NSString *result = [self stringByEvaluatingJavaScriptFromString:javaScriptString]; if(completionHandler) { completionHandler(result, nil); } } @end
  50. 50. UIWebView には足りないメソッドを実装する! // UIWebView+WKProtocolConformed.m #import "UIWebView+WKProtocolConformed.h" @implementation UIWebView (WKProtocolConformed) - (NSURL *)URL { NSString *URLString = [self stringByEvaluatingJavaScriptFromString:@"document.URL"]; return [NSURL URLWithString:URLString]; } - (NSString *)title { return [self stringByEvaluatingJavaScriptFromString:@"document.title"]; } - (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler { NSString *result = [self stringByEvaluatingJavaScriptFromString:javaScriptString]; if(completionHandler) { completionHandler(result, nil); } } @end loadRequest: などは元から実装されているのでスルー!
  51. 51. 準備はここまで (Obj-Cのことはもう忘れてOK)
  52. 52. Controller で WKWebViewProtocol 型として webView を保持 // MyViewController.swift import UIKit import WebKit class ViewController: UIViewController { var webView: WKWebViewProtocol! override func viewDidLoad() { super.viewDidLoad() self.createWebView() } func createWebView() { if NSClassFromString("WKWebView") != nil { let wkWebView = WKWebView(frame: self.view.bounds) self.view.addSubview(wkWebView) webView = wkWebView } else { let uiWebView = UIWebView(frame: self.view.bounds) self.view.addSubview(uiWebView) webView = uiWebView as WKWebViewProtocol } } …(続く)
  53. 53. Controller で WKWebViewProtocol 型として webView を保持 // MyViewController.swift import UIKit import WebKit class ViewController: UIViewController { var webView: WKWebViewProtocol! override func viewDidLoad() { super.viewDidLoad() self.createWebView() } func createWebView() { if NSClassFromString("WKWebView") != nil { let wkWebView = WKWebView(frame: self.view.bounds) self.view.addSubview(wkWebView) webView = wkWebView } else { let uiWebView = UIWebView(frame: self.view.bounds) self.view.addSubview(uiWebView) webView = uiWebView as WKWebViewProtocol } } …(続く) WKWebViewProtocol! 型として1個だけ変数を保持!
  54. 54. Controller で WKWebViewProtocol 型として webView を保持 // MyViewController.swift import UIKit import WebKit class ViewController: UIViewController { var webView: WKWebViewProtocol! override func viewDidLoad() { super.viewDidLoad() self.createWebView() } func createWebView() { if NSClassFromString("WKWebView") != nil { let wkWebView = WKWebView(frame: self.view.bounds) self.view.addSubview(wkWebView) webView = wkWebView } else { let uiWebView = UIWebView(frame: self.view.bounds) self.view.addSubview(uiWebView) webView = uiWebView as WKWebViewProtocol } } …(続く) インスタンス化の後は、WK / UI 共に変数 webView に格納できる!
  55. 55. Controller で WKWebViewProtocol 型として webView を保持 // MyViewController.swift …(続き) override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let URL = NSURL(string: "http://yahoo.co.jp") let req = NSURLRequest(URL: URL!) webView.loadRequest(req) } }
  56. 56. Controller で WKWebViewProtocol 型として webView を保持 // MyViewController.swift …(続き) override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let URL = NSURL(string: "http://yahoo.co.jp") let req = NSURLRequest(URL: URL!) webView.loadRequest(req) } } 以後は何の区別もなく同じ webView として扱える!
  57. 57. DEMO
  58. 58. 方針1: Wrapper で包む 方針2: UIWebViewをいじる • 特別なことをしていないので安心。 • だいぶ裏技っぽい。 (戻り値型を捻じ曲げてる辺り特に) • 全メソッドを実装して、それぞれ分岐 処理を書くのが面倒。 • UIWebViewで足りないメソッドだけ実 装すれば良い。
  59. 59. いつか iOS 7 のサポートを切るとき、 UIWebView と気持ち良く別れられるように。
  60. 60. 2014年12月 5日 Yahoo! JAPAN Tech Blog let UIWebView as WKWebView
  61. 61. Thanks! Blog: http://taketo1024.hateblo.jp Twitter: @taketo1024

×