Objective-C WKWebView:当 WebView 完成加载时,didFinish 未触发

Objective-C WKWebView: didFinish not triggering when WebView finishes loading

提问人:Diego Perez 提问时间:11/27/2022 最后编辑:halferDiego Perez 更新时间:12/13/2022 访问量:356

问:

我的应用程序是 Objective-C,我正在一点一点地迁移,所以我需要 Objective-C 而不是 Swift 方面的帮助。

我正在将 UIWebView 迁移到 WKWebView,但在使 didFinish 正常工作时遇到问题。

这是我使用 WebView TMAnswerView 的类:

#import "TMAnswerView.h"
#import "TMConsts.h"
#import "TMPersistanceManager.h"
#import <WebKit/WebKit.h>

@interface TMAnswerView () <WKNavigationDelegate>
//UIWebViewDelegate
@end

@implementation TMAnswerView.m

-(void)customInit{
        
}

-(void)setAnswer:(TMAnswerModel *)answer{
    
    _answer = answer;
    
    float font = 17;
    NSNumber *type = [TMPersistanceManager fetchObjectForKey:PERSettingsFontSize];
    if([type isEqual:SettingsFontSizeType1]){
        font = font * 0.75;
    }else if([type isEqual:SettingsFontSizeType3]){
        font = font * 1.25;
    }else if([type isEqual:SettingsFontSizeType4]){
        font = font * 1.5;
    }else if([type isEqual:SettingsFontSizeType5]){
        font = font * 2;
    }
    
    NSString *htmlBody = [TMUtils getHTMLStringForMath:[answer.answer stringByReplacingOccurrencesOfString:@"$$" withString:@"$"] andFontSize:(int)font];
    
    [_answerWebView loadHTMLString:htmlBody baseURL:[NSURL fileURLWithPath: [NSString stringWithFormat:@"%@/", [[NSBundle mainBundle] bundlePath]]]];
    _answerWebView.scrollView.contentInset = UIEdgeInsetsMake(0,-8,0,-8);
    
}

#pragma mark - click listeners

- (IBAction)onCheckButton:(id)sender {
    if(_viewControllerType != TMMainTestViewConstrollerTypeDoTest){
        return;
    }
    _checkButton.selected = !_checkButton.selected;
    if(_delegate){
        [_delegate onCheckChanged:_answer];
    }
}

- (void)webView:(WKWebView *)webView
didFinishNavigation:(WKNavigation *)navigation{
    [self setWebViewHeight];
}

//-(void)webViewDidFinishLoad:(WKWebView *)webView{
//    [self setWebViewHeight];
//}

-(void) setWebViewHeight{
    CGSize fittingSize = [_answerWebView sizeThatFits:CGSizeZero];
    _heightOfWebView.constant = fittingSize.height;
}

@end

在这里,我已将 UIWebView 委托替换为 WKNavigationDelegate。我不得不提一下,它与UIWebView的旧webViewDidFinishLoad配合得很好。

TMAnswerView.h:

#import "TMCustomView.h"
#import "TMAnswerModel.h"
#import "TMMainTestViewController.h"
#import <WebKit/WebKit.h>

@protocol TMAnswerViewProtocol <NSObject>

-(void) onCheckChanged:(TMAnswerModel*) answer;

@end

@interface TMAnswerView : TMCustomView

@property (nonatomic, strong) TMAnswerModel *answer;

@property (weak, nonatomic) IBOutlet UIButton *checkButton;
@property (weak, nonatomic) IBOutlet WKWebView *answerWebView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *heightOfWebView;

@property (weak, nonatomic) id<TMAnswerViewProtocol> delegate;

@property (nonatomic) TMMainTestViewConstrollerType viewControllerType;
-(void) setWebViewHeight;

@end

最后,在情节提要中,我添加了一个 WebKitView 元素来替换旧的 UIWebView。

我也尝试过didFinishNavigation,但无济于事。

我检查了下一页作为参考:

WKWebView(WKWebView)

我的代码有什么问题吗?如何触发 didFinish 事件?

编辑 1

我也试过:

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
    [self setWebViewHeight];
}

无济于事。

编辑 2

这是加载 WKWebView TMQuestionView 的类:

#import "TMQuestionView.h"
#import "TMColors.h"
#import "TMDBManager.h"
#import "TMConsts.h"
#import "TMAnswerModel.h"
#import "TMAnswerView.h"
#import "TMViewUtils.h"
#import "TMPersistanceManager.h"
#import "TMImagePreviewView.h"
#import <WebKit/WebKit.h>

@interface TMQuestionView () <TMAnswerViewProtocol, WKNavigationDelegate>

@property (weak, nonatomic) IBOutlet WKWebView *webView;
@property (weak, nonatomic) IBOutlet UIView *answersView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *webviewHeight;
@property (weak, nonatomic) IBOutlet UIView *viewForLoading;
@property (weak, nonatomic) IBOutlet UIView *loadingView;
@property (weak, nonatomic) IBOutlet WKWebView *webviewExplanations;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *webviewExplanationsHeight;

@property (nonatomic) BOOL isExplanationsVisible;

@property (nonatomic, strong) NSMutableArray *images;

@property (nonatomic, strong) NSString *tempic;

@end

@implementation TMQuestionView

-(void)customInit{
    
    [[CSLoadingManager sharedManager] addLoadingViewToView:_viewForLoading withColor:TMBaseColor(1)];
    _images = [NSMutableArray new];
    
}

-(void)setQuestion:(TMQuestionModel *)question{
    _question = question;
    
    float font = 17;
    NSNumber *type = [TMPersistanceManager fetchObjectForKey:PERSettingsFontSize];
    if([type isEqual:SettingsFontSizeType1]){
        font = font * 0.75;
    }else if([type isEqual:SettingsFontSizeType3]){
        font = font * 1.25;
    }else if([type isEqual:SettingsFontSizeType4]){
        font = font * 1.5;
    }else if([type isEqual:SettingsFontSizeType5]){
        font = font * 2;
    }
    
    [_images addObjectsFromArray:[TMUtils getImagesFromQuestion:question.question]];
    [_images addObjectsFromArray:[TMUtils getImagesFromQuestion:question.instructions]];
    
    NSString *htmlString = question.question;
    if(question.instructions.length > 0 && ![question.instructions isEqualToString:@"(null)"]){
        htmlString = [NSString stringWithFormat:@"%@<br/>%@", question.instructions, question.question];
    }
    NSString *htmlBody = [TMUtils getHTMLStringForMath:htmlString andFontSize:(int)font];
    htmlBody = [htmlBody stringByReplacingOccurrencesOfString:@"<center>" withString:@"<p style='text-align:center;'>"];
    htmlBody = [htmlBody stringByReplacingOccurrencesOfString:@"</center>" withString:@"</p>"];

    _tempic = htmlBody;
    
    [_webView loadHTMLString:htmlBody baseURL:[NSURL fileURLWithPath: [NSString stringWithFormat:@"%@/", [[NSBundle mainBundle] bundlePath]]]];
    _webView.scrollView.contentInset = UIEdgeInsetsMake(0,-8,0,-8);
    _answersView.hidden = YES;
    
    [[TMDBManager sharedManager] getAnswersForQuestion:_question completition:^(NSDictionary *dict) {
        
        NSArray *temp = [dict objectForKey:DBReturnAnswers];
        NSSortDescriptor *sortDescriptor;
        sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"answerNumber" ascending:YES];
        NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
        self->_answers = [temp sortedArrayUsingDescriptors:sortDescriptors];

        [self setViewAnswers];
    }];
    
}

-(void) setExplanations{
    _isExplanationsVisible = YES;
    float font = 17;
    NSNumber *type = [TMPersistanceManager fetchObjectForKey:PERSettingsFontSize];
    if([type isEqual:SettingsFontSizeType1]){
        font = font * 0.75;
    }else if([type isEqual:SettingsFontSizeType3]){
        font = font * 1.25;
    }else if([type isEqual:SettingsFontSizeType4]){
        font = font * 1.5;
    }else if([type isEqual:SettingsFontSizeType5]){
        font = font * 2;
    }
    NSString *htmlString = _question.explanation;
    NSString *htmlBody = [TMUtils getHTMLStringForMath:htmlString andFontSize:(int)font];
    [_webviewExplanations loadHTMLString:htmlBody baseURL:[NSURL fileURLWithPath: [NSString stringWithFormat:@"%@/", [[NSBundle mainBundle] bundlePath]]]];
    _webviewExplanations.scrollView.contentInset = UIEdgeInsetsMake(0,-8,0,-8);
}

-(void)setRecordAnswer:(TMRecordAnswerModel *)recordAnswer{
    _recordAnswer = recordAnswer;
}

-(void) setViewAnswers{
    int i = 0;
    
    float font = 17;
    NSNumber *type = [TMPersistanceManager fetchObjectForKey:PERSettingsFontSize];
    if([type isEqual:SettingsFontSizeType1]){
        font = font * 0.75;
    }else if([type isEqual:SettingsFontSizeType3]){
        font = font * 1.25;
    }else if([type isEqual:SettingsFontSizeType4]){
        font = font * 1.5;
    }else if([type isEqual:SettingsFontSizeType5]){
        font = font * 2;
    }
    
    for(TMAnswerModel *item in _answers){
        
        TMAnswerView *view = [[TMAnswerView alloc] init];
        view.translatesAutoresizingMaskIntoConstraints = NO;
        [_answersView addSubview:view];
        [[view.leadingAnchor constraintEqualToAnchor:_answersView.leadingAnchor constant:0] setActive:YES];
        [[view.rightAnchor constraintEqualToAnchor:_answersView.rightAnchor constant:0] setActive:YES];
        if(i == 0){
            [[view.topAnchor constraintEqualToAnchor:_answersView.topAnchor constant:0] setActive:YES];
        }else{
            UIView *lastView = [[_answersView subviews] objectAtIndex:i-1];
            [[view.topAnchor constraintEqualToAnchor:lastView.bottomAnchor constant:0] setActive:YES];
        }

        view.answer = item;
        view.delegate = self;
        view.viewControllerType = _viewControllerType;
                
        if(_recordAnswer){
            if(item.isCorrect == 1){
                if([_recordAnswer.selectedAnswerId isEqualToString:item.answerId]){
                    [view.checkButton setImage:[UIImage imageNamed:@"checkbox_checked"] forState:UIControlStateNormal];
                }else{
                    [view.checkButton setImage:[UIImage imageNamed:@"checkbox_checked_gray"] forState:UIControlStateNormal];
                }
            }else{
                if([_recordAnswer.selectedAnswerId isEqualToString:item.answerId]){
                    [view.checkButton setImage:[UIImage imageNamed:@"checkbox_error"] forState:UIControlStateNormal];
                }
            }
        }


        i++;
        
        if(i == [_answers count]){
            [[view.bottomAnchor constraintEqualToAnchor:_answersView.bottomAnchor constant:0] setActive:YES];
        }
    }
}

-(void)onCheckChanged:(TMAnswerModel *)answer{
    for (TMAnswerView *item in [_answersView subviews]){
        if(![item.answer isEqual:answer]){
            if(item.checkButton.selected){
                item.checkButton.selected = NO;
            }
        }
    }
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation{
    [self setHeightOfWebView];
}

//-(void)webViewDidFinishLoad:(WKWebView *)webView{
//    [self setHeightOfWebView];
//}

-(TMAnswerModel*) getSelectedAnswer{
    for (TMAnswerView *item in [_answersView subviews]){
        if(item.checkButton.selected){
            return item.answer;
        }
    }
    return nil;
}

-(void) setHeightOfWebView{
    _viewForLoading.hidden = YES;
    _loadingView.hidden = YES;
    CGSize fittingSize = [_webView sizeThatFits:CGSizeZero];
    _webviewHeight.constant = fittingSize.height;
    _answersView.hidden = NO;
    
    for(UIView *item in [_answersView subviews]){
        if([item isKindOfClass:[TMAnswerView class]]){
            [((TMAnswerView*) item) setWebViewHeight];
        }
    }
    
    if(_isExplanationsVisible){
        CGSize fittingSizeExplanations = [_webviewExplanations sizeThatFits:CGSizeZero];
        _webviewExplanationsHeight.constant = fittingSizeExplanations.height;
    }

}

- (IBAction)onButtonAboveWebViewClicked:(id)sender {
    if([_images count] > 0){

        TMImagePreviewView *view = [[TMImagePreviewView alloc] initWithFrame:CGRectMake(0, 0, kAppWidth, kAppHeight)];
        [view setImages:_images];
        [[[self superview] superview] addSubview:view];
        [view fadeIn];
        
    }
}

- (IBAction)onButtonTemp:(id)sender forEvent:(UIEvent *)event {
    NSSet *touches = [event touchesForView:sender];
    UITouch *touch = [touches anyObject];
    CGPoint touchPoint = [touch locationInView:[sender superview]];
    NSLog(@"%@", NSStringFromCGPoint(touchPoint));
    
    
    long htmlLength = _tempic.length;
    
    
    long heightOfWebView = _webView.frame.size.height;
    
    double percentTouch = (double)touchPoint.y / (double)heightOfWebView;
    
    
    int index = 0;
    
    for(NSString *imageStr in _images){
        NSString *match = [[imageStr componentsSeparatedByString:@"/"] objectAtIndex:1];
        NSRange rangeOfImage = [_tempic rangeOfString:match];
        
        double percentText = (double) rangeOfImage.location / (double)htmlLength;

        if(percentText > percentTouch){
            break;
        }
        index++;
        
    }
    
    NSLog(@"STOP");
    
}

@end
iOS Objective-C Xcode UIWebView wkwebview

评论

1赞 HangarRash 11/27/2022
您必须使用正确的方法签名才能使其工作。没有这样的委托方法。使用正确的名称(请参阅文档),它将起作用。你很接近,但还不完全正确。- (void)webView:(WKWebView *)webView didFinish:(WKNavigation *)navigation
0赞 Diego Perez 11/27/2022
这很有趣,因为你没有@HangarRash向我解释如何做到这一点。如果我问,应该是因为我不知道该怎么做。我敢肯定可能出了什么问题,但不知道是什么。我已经检查了文档,但我是 iOS 开发的新手,并且尽力而为。你能解释一下如何做到这一点,而不是引导我阅读文档吗?不过,感谢您的回复。
0赞 HangarRash 11/27/2022
我试图给你提示,这样你就可以自己看到问题所在。这是一种更好的学习方式。查看文档。文档中显示的委托方法的全名是什么?将其与代码中的内容进行比较。这是一个很小但很重要的区别。一字一句地看,就好像你以前从未见过它一样。校对你自己的作品是很困难的,因为你总是看到它应该是什么,而不是实际是什么。
0赞 HangarRash 11/27/2022
这里有一些更多建议。1) 将文档中的方法复制并粘贴到代码旁边,以查看差异。2)使用Xcode的代码补全,让它输入签名,避免犯这样的简单错误。
0赞 HangarRash 11/27/2022
好的,您最新的编辑现在显示了正确的方法。它没有被召唤吗?是否调用了任何其他导航委托方法?是否设置了导航委托?

答:

0赞 Ptit Xav 11/28/2022 #1

也许你可以在TMAnswerView.setAnswer中添加这个:

-(void)setAnswer:(TMAnswerModel *)answer {
    ...
    // set self as navigationDelegate for the webView
    _answerWebView.navigationDelegate = self;
    
    [_answerWebView loadHTMLString:htmlBody...
...