WKWebView заставляет мой контроллер просмотра протекать

Контроллер My View отображает WKWebView. Я установил обработчик сообщений, классную функцию веб-набора, которая позволяет уведомлять мой код изнутри веб-страницы:

override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) let url = // ... self.wv.loadRequest(NSURLRequest(URL:url)) self.wv.configuration.userContentController.addScriptMessageHandler( self, name: "dummy") } func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { // ... } 

Пока все хорошо, но теперь я обнаружил, что мой контроллер представления протекает – когда он должен быть освобожден, это не так:

 deinit { println("dealloc") // never called } 

Похоже, что просто установка себя как обработчика сообщений вызывает цикл удержания и, следовательно, утечку!

3 Solutions collect form web for “WKWebView заставляет мой контроллер просмотра протекать”

Правильно, как обычно, король в пятницу. Оказывается, WKUserContentController сохраняет свой обработчик сообщений . Это делает определенный смысл, поскольку он вряд ли может отправить сообщение своему обработчику сообщений, если его обработчик сообщений перестает существовать. Это параллельно тому, как CAAnimation сохраняет свой делегат, например.

Однако он также вызывает цикл удержания, поскольку сам WKUserContentController протекает. Это не имеет большого значения само по себе (это всего лишь 16K), но цикл сохранения и утечка контроллера вида являются плохими.

Мое обходное решение заключается в том, чтобы вставить объект батута между WKUserContentController и обработчиком сообщений. Объект батута имеет лишь слабое отношение к вещественному обработчику сообщений, поэтому нет цикла сохранения. Вот объект батута:

 class LeakAvoider : NSObject, WKScriptMessageHandler { weak var delegate : WKScriptMessageHandler? init(delegate:WKScriptMessageHandler) { self.delegate = delegate super.init() } func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { self.delegate?.userContentController( userContentController, didReceiveScriptMessage: message) } } 

Теперь, когда мы устанавливаем обработчик сообщений, мы устанавливаем объект батута вместо self :

 self.wv.configuration.userContentController.addScriptMessageHandler( LeakAvoider(delegate:self), name: "dummy") 

Оно работает! Теперь вызывается deinit , доказывая, что утечки нет. Похоже, что это не должно работать, потому что мы создали объект LeakAvoider и никогда не ссылались на него; но помните, что сам WKUserContentController сохраняет его, поэтому проблем нет.

Для полноты, теперь, когда вызывается deinit , вы можете удалить обработчик сообщений там, хотя я не думаю, что это действительно необходимо:

 deinit { println("dealloc") self.wv.stopLoading() self.wv.configuration.userContentController.removeScriptMessageHandlerForName("dummy") } 

Решение, посланное матом, – вот что нужно. Думаю, я перевел бы его на объектный код c

 @interface WeakScriptMessageDelegate : NSObject<WKScriptMessageHandler> @property (nonatomic, weak) id<WKScriptMessageHandler> scriptDelegate; - (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate; @end @implementation WeakScriptMessageDelegate - (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate { self = [super init]; if (self) { _scriptDelegate = scriptDelegate; } return self; } - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { [self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message]; } @end 

Затем используйте его так:

 WKUserContentController *userContentController = [[WKUserContentController alloc] init]; [userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"name"]; 

Утечка вызвана userContentController.addScriptMessageHandler(self, name: "handlerName") которая будет содержать ссылку на обработчик сообщения self .

Чтобы предотвратить утечку, просто удалите обработчик сообщения через userContentController.removeScriptMessageHandlerForName("handlerName") когда он вам больше не нужен. Если вы добавите addScriptMessageHandler в viewDidAppear , рекомендуется удалить его в viewDidDisappear .

  • Включить кеш приложений в WKWebView
  • Как проверить, заканчивается ли загрузка WkWebView в Objective-C?
  • WKWebView не возвращает правильную высоту размера контента
  • Универсальные ссылки, не работающие с WKWebView
  • Может ли WKWebView сохранять разрешение служб местоположения?
  • Прозрачный фон для WKWebView
  • WKWebView не открывается НЕКОТОРЫЕ target = "_ blank" ссылки
  • Как очистить историю в WKWebView?
  • Миграция из UIWebView в WKWebView
  • Кэш для WKWebView
  • Очистка WkWebview между запросами
  • Interesting Posts

    На iOS, почему высота кадра вида остается почти одинаковой после вращения?

    О AttributeString – создание нескольких случаев жирным шрифтом

    Почему я не могу использовать новый встроенный синтаксис #imageLiteral в Xcode 8? «Ожидаемое выражение в обратном результате»

    Как заставить мое представление, которое манипулирует UIPushBehavior, не вращается так сильно? Это абсурдная сумма

    NSMutableArray removeAllObjects вызывает сбой

    Как определить, установлено ли у пользователя приложение iOS?

    Приложение iPhone: не возобновление аудио сессии в AVAudio Player

    Как загрузить все представления в UITabBarController?

    Условная компиляция с ifndef и || не улавливает второй случай

    Видео thumbnail перемещение для вставки изображения с использованием jwplayer видео встроенный контент Html в веб-виде от навигации в быстром

    Получить из базы данных базы данных огней

    не удается найти каталог / var / mobile / applications для документов ios

    MPMoviePlayerController медленное движение вперед и назад

    iOS 6 Xcode 4.5 неподдерживаемая архитектура armv7s

    UILabel – сокращенный текст вместо усеченного хвоста

    PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.