我在UITable中的每个UITableViewCell中使用UIWebView作为附件视图,以便在每个表视图中显示一个小的Openlayers映射。当我第一次显示表视图时,第一个单元格中的UIWebView显示地图正常,但所有其他单元格中的其他UIWebViews都是空的。
如果我上下滚动表格,那么其他单元格在返回视图时都会正常加载,每个单元格都有不同的小地图。
UIWebViews每个都在init上加载一个初始的HMTL文档,这个文档包含标准的Openlayers ol.js javascript。
附件视图UIView子类是UIWebView的委托,等待它加载,然后发送另一个javascript来绘制地图功能。
登录此委托方法会显示网络视图loaded
属性为YES / TRUE,但javascript readyState
仍为loading
。
为什么会这样?我怎样才能按预期工作?
通过调用loadHTMLString:baseURL:
方法中的drawRect:
,告知webView加载通用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
状态为真,对于FIRST CELL而言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,但是委托方法在它准备就绪后永远不会被调用。
如何在不诉诸延迟执行的狡猾解决方法的情况下让这个按预期工作?
更新替代方法
这是另一个试图让这个工作的版本,部分基于来自@ Ricowere答案的想法(类似于我在开始drawRect:
hack之前的开始
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 :(得分: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.
}
}
答案 1 :(得分: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稍慢,这很奇怪,但至少它没有错误,没有任何狡猾的工作。