2017-02-26 45 views
0

我在UITable中的每个UITableViewCell中使用一个UIWebView作为附件视图,以便在每个表格视图中显示一个小型的Openlayers地图。当我第一次显示表格视图时,第一个单元格中的UIWebView显示地图正常,但所有其他单元格中的其他UIWebViews都是空的。UITableViewCell中的UIWebView只完成第一个单元格中的加载

如果我上下滚动表格,那么其他单元格在加载到视图中时都会正常加载,每个单元格都带有各自不同的小地图。

UIWebViews每个都在init中加载一个初始HMTL文档,并且此文档包含标准Openlayers ol.js javascript。

附件视图UIView子类是UIWebView的委托并等待它加载,然后再发送另一个JavaScript来绘制地图特征。

登录此代理方法显示web视图loaded属性为YES/TRUE,但javascript readyState仍为loading

这是为什么?我如何才能按预期工作?

通过从drawRect:方法中调用loadHTMLString:baseURL:来告知webView加载通用HTML/javascript。然后使用委托方法检查加载何时完成,以便在通用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运行,并且它依赖于标准的OpenLayers(ol.js)的JavaScript在初始HTML网页已经完成)。

输出是:

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查看它加载完成的事情,所以这个委托方法不会再被调用。

解决的作品:

我可以解决此问题通过取消注释是在上面的委托方法注释掉performSelector:withObject:afterDelay:。这表明HTML确实最终会加载OK,但是在真正准备好之后,委托方法永远不会被调用。

如何在没有诉诸延迟执行的可靠解决方法的情况下按预期工作?

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答案的想法,但是使用UITableView委托而不是UITableViewCell子类,并且在Objective C而不是Swift中完成。

这里是结束了工作对我来说...

在我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中的代码。这种方法完全错误,你把商业逻辑放在绘图方法中。 (这是执行一次,然后细胞被重用)

在这里,我告诉你一个简单的方法来解决这个问题。

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

啊bollocks ....在奖励你100个赏金点后,我意识到我仍然有我的延迟执行工作。删除这项工作后,它仍然无法正常工作。事实上,它很像我在尝试'drawRect:'之前开始的。在我的问题中看到我的更新,看看我现在在做什么(不是你发布的内容,而是相同的想法,我想?)。我相信问题是,现在仍然是,当所有这些代码被调用时,单元格及其附属视图在屏幕上并不实际可见,并且UIWebView在不在屏幕上时不加载HTML。 –

+0

你有问题(主要的)是你有一个有限的功能与UIWebView和注入Javascript工作。改用WKWebView。 (这一个将尊重DOM加载) 我已经上传了一个开放图层的例子正常工作[这里](https://gist.github.com/Ricowere/c247e17d64adc51c634ebf2bc63e56c7)。看看这[帖子](http://nshipster.com/wkwebkit/)也。关于您提供的解决方案,请再次查看,因为您重新使用单元格的方式不正确。您每次都创建'StyleViewUIWebViewSubclass',而不是重复使用它。希望它绝对有帮助!:) – Ricowere

+0

好的,它现在工作,使用WKWebView而不是UIWebView。我使用UIWebView为了调试目的而获取它的javascript上下文(我不知道我是否可以用WKWebView做,而且比通过Safari做这件事要好得多),但是现在我的javascript已经正常了,所以不再需要这个了。虽然WKWebView在所有单元格的内容加载之前大约需要2秒钟,但速度很慢。但它会做的。我会发布我的解决方案作为答案,以表明我做了什么。 –

相关问题