2017-02-26 2 views
0

私は各テーブルビューに小さなOpenlayersマップを表示するために、UITableの各UITableViewCellのアクセサリビューとしてUIWebViewを使用しています。最初にテーブルビューを表示すると、最初のセルのUIWebViewはマップを表示しますが、ほかのすべてのセルのUIWebViewは空です。UITableViewCellのUIWebViewは、最初のセルのロードを完了するだけです

テーブルを上下にスクロールすると、表示されたときに別の小さなマップが表示されたときに、他のセルがすべて正常に読み込まれます。

UIWebViewsはinitで初期HMTLドキュメントを読み込み、このドキュメントには標準のOpenlayers ol.js javascriptが含まれています。

アクセサリビューUIViewサブクラスは、UIWebViewのデリゲートであり、マップフィーチャを描画する別のjavascriptを送信する前に、UIWebViewがロードされるのを待ちます。

このデリゲートメソッドでログインすると、WebビューloadedのプロパティはYES/TRUEですが、JavaScriptのreadyStateはまだloadingです。

これはなぜでしょうか?これを期待どおりにするにはどうすればよいですか?

webViewは、drawRect:メソッド内からloadHTMLString:baseURL:への呼び出しを介して汎用HTML/javascriptを読み込むように指示されます。次に、webViewDidFinishLoad:デリゲートメソッドを使用して、読み込みが完了したことを確認し、汎用HTML/javascriptの完了後にセル固有のjavascriptを実行できるようにします。

- (void)drawRect:(CGRect)rect { 
    NSString *path = [NSBundle pathForResource:@"style" ofType:@"html" inDirectory:[[NSBundle mainBundle] bundlePath]]; 
    NSString *html = [NSString stringWithContentsOfFile:path usedEncoding:nil error:nil]; 

    [_webView loadHTMLString:html baseURL:[NSURL fileURLWithPath:[path stringByDeletingLastPathComponent] isDirectory:YES]]; 
} 

- (void)webViewDidFinishLoad:(UIWebView *)webView { 
    if (! _webView.loading) { 
     if ([[webView stringByEvaluatingJavaScriptFromString:@"document.readyState"] isEqualToString:@"complete"]) { 
      NSLog(@"All good"); 
      [self drawFeatures]; 
     } else { 
      NSLog(@"ERROR: webView loaded, readyState '%@'", [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"]); 
      //[self performSelector:@selector(drawFeatures) withObject:nil afterDelay:0.5]; 
     } 
    } 
} 

[self drawFeatures]は、いくつかのJavaScriptを組み立て、実行するためのUIWebViewに送信し、それが最初のHTMLウェブページに完成した標準OpenLayersを(ol.js)はJavaScriptに依存しています:

関連するコードです)。

出力は次のようになります。

2017-02-26 15:15:00.071 myapp[50443:25603667] ERROR: webView loaded, readyState 'loading' 
2017-02-26 15:15:00.093 myapp[50443:25603667] ERROR: webView loaded, readyState 'loading' 
2017-02-26 15:15:00.116 myapp[50443:25603667] ERROR: webView loaded, readyState 'loading' 
2017-02-26 15:15:00.132 myapp[50443:25603667] ERROR: webView loaded, readyState 'loading' 
2017-02-26 15:15:00.148 myapp[50443:25603667] ERROR: webView loaded, readyState 'loading' 
2017-02-26 15:15:00.166 myapp[50443:25603667] ERROR: webView loaded, readyState 'loading' 
2017-02-26 15:15:00.190 myapp[50443:25603667] ERROR: webView loaded, readyState 'loading' 
2017-02-26 15:15:00.208 myapp[50443:25603667] ERROR: webView loaded, readyState 'loading' 
2017-02-26 15:15:00.226 myapp[50443:25603667] ERROR: webView loaded, readyState 'loading' 
2017-02-26 15:15:00.245 myapp[50443:25603667] ERROR: webView loaded, readyState 'loading' 
2017-02-26 15:15:00.262 myapp[50443:25603667] ERROR: webView loaded, readyState 'loading' 
2017-02-26 15:15:00.292 myapp[50443:25603667] All good 

あなたは、この出力からわかるように、ほとんどの細胞のためのisLoaded状態はisLoadedが本当に本当にされた後、最後まで来た(最初のセルのための真になる前に真であります実際に準備が整っています)。これは、Webビューは実際にはないときにロードされたと考えていることを意味します。

呼び出されないので、何のHTML /のUIWebViewの誤りがないように思われます決して読み込みエラーデリゲートメソッド:

-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { 
    NSLog(@"ERROR loading style view HTML:\n%@", [error description]); 
} 

注私は、デリゲートメソッドを変更した場合のみ、javascriptをreadyStateをチェックして、isLoadingを無視していること値は、私はreadyState完了の決して得ることはありません。ただloading。おそらく、これは、Webの読み込みが完了しているので、このデリゲートメソッドが再度呼び出されないためです。 WORKS AROUND

WORK:

は、私は上記のデリゲートメソッドではコメントアウトされている。performSelector:withObject:afterDelay:のコメントを外すことで問題を回避することができます。これは、HTMLが最終的にはOKをロードするが、デリゲートメソッドは実際に準備ができた後では呼び出されないことを示しています。

perform-with-delayの回避策に頼ることなく、これを期待どおりに動作させるにはどうすればよいですか?別の方法

を試し

UPDATEはここでは、この作業を取得しようとしているの別のバージョンは、部分的にRicowereの回答@からアイデア(と私はdrawRect:ハック

のために行く前に開始したものと同様に基づいて、です。

HTMLの読み込みが私のUIWebViewサブクラスのメソッドになりました。この場合は、適切な方法は、私はそれのUIWebViewサブクラスのプロパティを設定するときです:

- (void)setStyle:(RenderStyle *)style { 
    _style = style; 

    ... 
    ... 

    NSString *path = [NSBundle pathForResource:@"style" ofType:@"html" inDirectory:[[NSBundle mainBundle] bundlePath]]; 
    NSString *html = [NSString stringWithContentsOfFile:path usedEncoding:nil error:nil]; 

    [self loadHTMLString:html baseURL:[NSURL fileURLWithPath:[path stringByDeletingLastPathComponent] isDirectory:YES]]; 
} 

次に、テーブルビューデリゲートで、テーブルビューセルがデキューされるたびに、アクセサリビューとしてUIWebViewサブクラスビューを追加し、そのUIWebViewサブクラスビューに対して、HTMLをロードするプロパティメソッドを呼び出します。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"styleCell"]; 

    if (cell == nil) { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"styleCell"]; 
     ... 
     ... 
    } 

    ... 
    ... 
    StyleViewUIWebViewSubclass *styleView = [[StyleViewUIWebViewSubclass alloc] initWithFrame:frame]; 

    cell.accessoryView = styleView; 

    styleView.style = [[RenderStyle alloc] initWithString:styles[styleName]]; 

    return cell; 
} 

ただし、これには同じ問題があります。それを動作させるには、上記の演奏遅延演奏がまだ必要です。

答えて

0

@Ricowereのヒントのおかげで、私はこれを実現しました。私の解決策は@Ricowereの回答のアイデアに基づいていますが、UITableViewCellサブクラスの代わりにUITableViewデリゲートを使用し、Swiftの代わりにObjective Cですべて実行します。ここで

は...私のために働いてしまったものを私のWKWebViewサブクラスで

です:

- (id)initWithFrame:(CGRect)frame { 
    if (self = [super initWithFrame:frame]) { 
     ... 
     self.navigationDelegate = self; 
    } 

    return self; 
} 

- (void)setStyle:(RenderStyle *)style { 
    _style = style; 

    NSURL *url = [NSBundle URLForResource:@"style" withExtension:@"html" subdirectory:nil inBundleWithURL:[[NSBundle mainBundle] bundleURL]]; 

    [self loadFileURL:url allowingReadAccessToURL:[url URLByDeletingLastPathComponent]]; 
} 

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { 
    [self drawFeatures]; // This line runs the secondary instance-dependant javascript that relies on the generic javascript already having been completed 
} 

その後、私のUITableViewDelegateに:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"styleCell"]; 

    if (cell == nil) { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"styleCell"]; 
     ... 
     WKWebViewSubclass *styleView = [[WKWebViewSubclass alloc] initWithFrame:frame]; 

     cell.accessoryView = styleView; 
    } 

    ... 
    ((WKWebViewSubclass *)cell.accessoryView).style = [[RenderStyle alloc] initWithString:styleString]; 

    return cell; 
} 

それよりも少し遅くを実行しているようですUIWebViewは奇妙ですが、少なくともエラーなしで動作します。

1

まず、drawRectのコードを削除します。そのアプローチは完全に間違っています。あなたは抽象メソッドにbussinessロジックを入れています。 (これは1回実行され、その後にセルが再利用されます)

ここでは、これに取り組む簡単な方法を示します。

class CellExample: UITableViewCell, UIWebViewDelegate { 
    var accessoryWebView: UIWebView? { 
     return accessoryView as? UIWebView 
    } 

    //If you're dequeuing the cell from IB. 
    override func awakeFromNib() { 
     // Set the frame you need or do this through autolayout. 
     let webView = UIWebView(frame: CGRect(x: 0, y: 0, width: 50, height: 50)) 
     accessoryView = webView 
    } 

    //You have to call this everytime a cell is dequeued 
    //(Then the content is properly displayed again.) 
    func load(url: URL) { 
     accessoryWebView?.delegate = self 

     //Load the request or the HTML content as you need. 

     //accessoryWebView?.loadHTMLString("whatever", baseURL: URL(string: "whatever")!) 
//  accessoryWebView?.loadRequest(URLRequest(url: url, 
//            cachePolicy: .returnCacheDataElseLoad, 
//            timeoutInterval: 10)) 
    } 

    override func prepareForReuse() { 
     super.prepareForReuse() 

     //If the cell is reused 'restart' the stack. 
     accessoryWebView?.delegate = nil 
     accessoryWebView?.stopLoading() 
    } 

    func webViewDidFinishLoad(_ webView: UIWebView) { 
     // Do the stuff you need about the javascript. 
    } 
} 
+0

ああ、あなたは100ポイントの賞金を授与した後、私はまだ私の演奏とディレイの両方の作業を行っていたことに気付きました。この回避策を取り除いた後も、それはまだ機能しません。実際には、 'drawRect:'を試す前に私が始めたものとよく似ています。私が今何をしようとしているのかを私の質問で私の更新を見てください(あなたが投稿したものではありませんが、同じアイデアだと思います)。私は、このコードがすべて呼び出されたときに、セルとアクセサリビューが実際に画面に表示されないことが問題であったと考えています。また、UIWebViewは画面にHTMLが表示されません。 –

+0

あなたが持っていた問題(主なもの)は、UIWebViewを操作してJavascriptを注入する機能が限られていることです。代わりにWKWebViewを使用してください。 (これはDOM読み込みを尊重します) 公開レイヤーの例が正しく[ここ](https://gist.github.com/Ricowere/c247e17d64adc51c634ebf2bc63e56c7)にアップロードされました。この[投稿](http://nshipster.com/wkwebkit/)もご覧ください。あなたが提供したソリューションについて、あなたが細胞を再利用する方法が間違っているので、もう一度それを見直してください。それを再利用するのではなく、毎回 'StyleViewUIWebViewSubclass'を作成しています。それが間違いなく助けて欲しい!:) – Ricowere

+0

OK、UIWebViewではなくWKWebViewを使用しています。私はUIWebViewを使用してデバッグ目的のJavaScriptコンテキストを取得していましたが(WKWebViewを使用できるかどうかわかりませんが、Safariを使って行うよりもずっと面白いですが)、今はjavascriptをOKにしていますもうそれは必要ありません。 WKWebViewは遅いです...すべてのセルの内容が読み込まれる前に約2秒かかります。しかし、それは行います。私は、私が行ったことを示すための答えとして私の解決策を掲示します。 –

関連する問題