Родовая травма интернета

В ходе профессиональной деятельности часто сталкиваюсь с языком программирования Джаваскрипт. И чем дольше я с ним сталкиваюсь (а впервые я с ним столкнулся в 1998 году, и с тех пор продолжаю сталкиваться), тем сильнее меня мучает невыносимая догадка, что всё происходящее — розыгрыш, зашедший слишком далеко.

Представьте, что после распада Союза в качестве государственного гимна временно утвердили песню группы Король и Шут «Прыгну со скалы» (вполне в духе времени, к слову сказать). И как-то одно за другое, туда-сюда, в общем, так эта песня и осталась гимном. Прошло много лет, специально обученные высококвалифицированные люди написали новый гимн, более подходящий серьезному государству. Но пока все поголовно граждане не будут знать новый гимн наизусть, утверждать его нельзя. Вот и проговаривают про себя, прижав руку к сердцу: «Быть таким, как все, с детства не умел, видимо, такой в жизни мой удел». Что поделать. Все привыкли.

Именно эта аналогия лучше всего описывает нынешнее положение дел в разработке под браузер. Если есть хотя бы какая-то вероятность конверсии с пользователей Интернет Эксплорера шестой версии (я сознательно упрощаю), а конверсия не пахнет, то приходится пользоваться технологиями двадцатипятилетней давности. Самую малость лучше (лишь самую) дела обстоят с серверным программированием, где можно использовать современный синтаксис Джаваскрипта. Вот только автор серверной платформы node.js недавно покаялся в грехах и пообещал сделать ноду нормально, что немедленно вызвало бурю негодования у дебилов: как так, что значит, нода плоха?

Ничего подобного в уровне отрицания объективной реальности я еще ни у кого не видел (если, конечно, не скатываться в обсуждение политических тем).

А разгадка одна.

Теги: программирование, javascript

Почему не работает таймер в Swift?

Предположим, вы сделали

и отправились по своим делам, а таймер отработал один раз или вообще не отработал. Почему? А потому, что объект timer зажевал сборщик мусора, а при деинициализации DispatchSourceTimer, разумеется, останавливает своё дальнейшее выполнение. Напомню, сборщик мусора всегда отрабатывает в конце области выполнения, то есть, в данной ситуации, по окончанию блока, переданного в async. Таким образом, если вы хотите регулярно выполнять какую-то задачу, необходимо класть указатель на объект таймера в известное глобальное место, которое проживет столько, сколько захочется вам, а не сборщику мусора. Желательно также организовать синхронный и потоко-безопасный доступ к этому месту с помощью последовательной очереди выполнения, чтобы избежать постыдных гонок за доступ.

Кстати, следует отметить, что существует и обратная ситуация: таймер отказывается удаляться, когда вы удалите все ссылки на него. Это может быть оттого, что хендлер таймера может держать сильную ссылку на какой-нибудь класс или self. Чтобы этого избежать, указывайте [weak self] в начале хендлера таймера.

Теги: программирование, swift

Секрет Self в Swift

Обновление 2019 года: в версии 5.1 Self можно будет использовать в конкретном контексте, а не только в протоколе и его расширениях. Как только версия 5.1 официально зарелизится, я обновлю эту заметку. А пока она отражает реалии Свифта до версии 5.1.

Изучающие язык программирования Swift наверняка знают, что означает ключевое слово self — это указатель на текущий объект внутри экземпляра класса. Совершенно нормальный функционал практически любого объектного языка. Сложности у обывателя могут начаться в момент, когда он сталкивается со статическими методами и свойствами, а также со знаменитой протокольно-ориентированной парадигмой этого языка. Не будем акцентироваться на особенностях протокольной философии, а приступим к самому интересному, с чем наверняка сталкивался всякий.

Я говорю о вызове статического метода из расширения протокола или определении метода протокола, который должен вернуть конечный тип (eventual type). Всё это является частным случаем позднего статического связывания, о котором всякий может нагуглить достаточно материала.

В случае с банальными статическими методами внутри класса или структуры всё просто — метод легко вызвать по названию типа или вызвать функцию type(of: self), которая вернет текущий тип, у которого уже можно вызывать статические методы. Однако если конкретного типа еще нет, а есть только протокол и/или его расширения (то бишь метатип), то язык не даст нам этого сделать, ведь протокол не может содержать реализации, а расширение протокола не считается конкретным кодом, и мы получаем ошибку Static member 'staticMethodName' cannot be used on protocol metatype 'ProtocolName.Protocol'.

Решением является использование ключевого слова Self (именно с большой буквы), которое является указателем на конечный тип, который реализует протокол. В официальной документации языка есть только одно упоминание этого ключевого слова:

In that [protocol] context, Self refers to the eventual type that conforms to the protocol.

Соответственно, работает это ключевое слово только в метатипах (протоколах и их расширениях), а в конкретных классах или структурах вы получите ошибку Use of unresolved identifier 'Self'.

Теги: программирование, swift, self