Да, это фантастический протокол Transferable. Тоже работаю над статьей о Transferable. для своего блога. Но чтобы это оценить, надо понимать, что было до появления этого протокола, то есть до iOS 16+.
За операции Drag & Drop (перетаскивание и "сброс") отвечал класс class NSItemProvider. Именно этот класс делает очень сложные вещи, связанные с передачей данных между процессами. Он также решает проблемы с безопасностью и определенно там есть многопоточность, потому что мы не хотим блокировать UI двух приложений в случае передачи между ними больших по объему изображений.
К сожалению, класс NSItemProvider — это до-Swift класс, и мы должны использовать “as” как “мостик” между такими Swift ТИПами как String, и такими ТИПами старого NS Мира, как NSString, это Objective-C вещи, и “as” является “мостом” в этот старый мир. До появления протокола Transferable технология Drag & Drop (перетаскивание и сброс) была одним из таких мест соприкосновения "старого" и нового Миров.
Почти параллельно с вашей статьей появились две статьи об опыте использования протокол Transferable :
Единственное, до чего не "дотягивает" протокол Transferable и соответствующий ему View модификатор dropDestination(for:action:isTargeted:), это возможность указания нескольких UTType.
Класс Operation имеет метод cancel(), однако использование этого метода только устанавливает свойство isCancelled в true, а что семантически означает «удаление» операции можно определить только при создании subclass Operation. Например, в случае загрузки данных из сети можно определить cancel() как отключение операции от сетевого взаимодействия.
Посмотрите мою другую статью "Concurrency в Swift 3 и 4. Operation и OperationQueue" в Habr, специально посвященную Operation.
Пожалуй, действительно не стоит обсуждать эффективное хранение структур structтем более в Standard Library.
В документации по Swift вовсе не сказано напрямую, что оптимизация хранения структур struct типа массивов Array, словарей Dictionary и строк String предполагает использование "кучи" (heap), там лишь сказано, что используется оптимизация для уменьшения затрат на копирование. Вместо того, чтобы делать копию немедленно, эти коллекции совместно используют память, в которой хранятся элементы, между исходным экземпляром и любыми копиями. Если одна из копий коллекции изменяется, элементы копируются непосредственно перед изменением.
Так что Apple оставляет за собой право, как она будет оптимизировать хранение структур struct, может и изменить это в любой момент времени.
Для нас важно лишь то, что в нашем коде ВСЕГДА у структуры struct будет такое поведение при изменении, как если бы копия была создана немедленно.
По большому счету структуры structявляются "неизменяемыми" (immutable) структурами данных в отличие от классов class.
Именно на основе того, что при любом изменении структуры structмы всегда имеем её новый экземпляр,и строится функциональное программирование.
Это особенно видно в новом фреймворке SwiftUI, в котором архитектура строится на основе MVVM, где View - всегда структуры struct, а ViewModels - классы class. Программирование в SwiftUI - это функциональное программирование.
Вы сами задаете интервал обновления.
А в fetch() уже работает @Published, а точнее CurrentValueSubject<Set, Never>([]), но это близко к @Published, и это воздействует на View SwiftUI.
У меня нет опыта работы с RxSwift, но многие отмечают, что хотя Combine пока по функциональности уступает RxSwift, он существенно превосходит RxSwift по быстродействию. Да это и понятно, ведь RxSwift написан поверх Swift, а Combine — ниже Foundation.
Лично меня поразило быстродействие связки Combine+ SwiftUI в задаче выборки данных о фильмах и их кинопостерах, что относится к ресурсо- затратным задачам. В том примере, который приведен в этой статье, при переходе от одной коллекции фильмов ( от тех, которые сейчас на экране, к популярным), выборка данных происходит столь быстро, что даже нет необходимости в экране «Loading...». «Сто лет» занимаюсь этими задачами и Combine+ SwiftUI преподнесли мне приятный сюрприз.
Да, я знаю, что одним из критериев конкурса было быстродействие.
Я конечно, не замеряла, но быстродействие очень хорошее.
Те, кто специально этим занимался отмечают существенное быстродействие по сравнению с UIKit.
Что касается навигации, то есть одно очень хорошее решение «Recreation of calculator-checklist project in SwiftUI», где очень просто воссоздается CustomSegue:
В Swift массивы Array являются структурами struct и Value ТИПАМИ. В Swift Value ТИПЫ хранятся в стеке.
Каждый поток имеет свое собственное пространство стека, поэтому никакой другой поток не сможет напрямую получить доступ к вашему Value ТИПУ. Следовательно, нет условий для гонки, блокировок, взаимных блокировок или каких-то других сложностей, связанных с синхронизацией потоков.
Если массив Array — очень большой, то для них использует механизм «Copy-on-Write».
Когда вы изменяете (например, добавляете append элементы) массив Array, он использует стандартную библиотечную функцию «isUniquelyReferenced», чтобы увидеть, есть ли какие-либо другие массивы, указывающие на буфер, к которому он собирается добавить. Если они есть, он делает копию, и копия становится ее новым резервным хранилищем. Это называется «Copy-on-Write».
Конечно, в императивном коде вы можете каждый раз создавать новый массив. Даже более того, если вы посмотрите на все эти map, flatMap, filter , то увидите, что именно так они и реализованы, никакой магии тут нет.
Но если вы находитесь в пределах императивного кода, то вам самому нужно все время контролировать себя, не делаете ли вы каких-то изменений «по месту».
Использование же функционального кода вам точно гарантирует «неизменяемость» за счет создания новых массивов ( или последовательностей или еще чего-нибудь) в функциях «высшего порядка».
Теперь map перевыбрасывает (rethrows) ошибку.
Но во всех постах очень известного сайта по функциональному программированию на Swiftpointfree.com во всех map перед transform стоит @escaping.
Но, похоже, вы правы и наличие @escaping сейчас является артефактом с прошлой версии.
Исправим.
По условиям задачи из массива [6, 22, 8, 14, 16, 0, 7, 9]:
— удаляется элемент с индексом 2, то есть 8
— удаляется элемент с индексом 5, то есть 0
— удаляется элемент с индексом 0, то есть 6
— удаляется элемент с индексом 6, то есть 7
И остается [22, 14, 16, 9]
Было восемь элементов, удалили четыре — осталось четыре
Считает все правильно — посмотрите на Playground.
Одна из причин использования @escaping — асинхронное выполнение кода. Если вы используете замыкание асинхронно с помощью DispatchQueгу, то очередь queue будет удерживать ваше замыкание в памяти для того, чтобы использовать его в будущем. В этом случае вы не можете точно сказать, когда замыкание будет выполнено. Все Generic map имеют @escaping замыкание, так как заранее неизвестно в какой среде вы будете его использовать.
По-моему как раз наоборот: сразу видны все Swift ключевые слова и легче соориентироваться.
Исправлено. Repository был private
Да, это фантастический протокол Transferable. Тоже работаю над статьей о Transferable. для своего блога. Но чтобы это оценить, надо понимать, что было до появления этого протокола, то есть до iOS 16+.
За операции Drag & Drop (перетаскивание и "сброс") отвечал класс class NSItemProvider. Именно этот класс делает очень сложные вещи, связанные с передачей данных между процессами. Он также решает проблемы с безопасностью и определенно там есть многопоточность, потому что мы не хотим блокировать UI двух приложений в случае передачи между ними больших по объему изображений.
К сожалению, класс NSItemProvider — это до-Swift класс, и мы должны использовать “as” как “мостик” между такими Swift ТИПами как String, и такими ТИПами старого NS Мира, как NSString, это Objective-C вещи, и “as” является “мостом” в этот старый мир. До появления протокола Transferable технология Drag & Drop (перетаскивание и сброс) была одним из таких мест соприкосновения "старого" и нового Миров.
Почти параллельно с вашей статьей появились две статьи об опыте использования протокол Transferable :
First Experience With Transferable Implementing Drag And Drop In SwiftUI
Transferable Protocol in SwiftUI – Transferring Alternative Content With ProxyRepresentation
Единственное, до чего не "дотягивает" протокол Transferable и соответствующий ему View модификатор dropDestination(for:action:isTargeted:), это возможность указания нескольких UTType.
Раньше, до iOS 16+:
Теперь, начиная с iOS 16+:
Но выход есть:
Класс
Operationимеет методcancel(), однако использование этого метода только устанавливает свойствоisCancelledвtrue, а что семантически означает «удаление» операции можно определить только при созданииsubclass Operation. Например, в случае загрузки данных из сети можно определитьcancel()как отключение операции от сетевого взаимодействия.Посмотрите мою другую статью "Concurrency в Swift 3 и 4. Operation и OperationQueue" в Habr, специально посвященную
Operation.https://habr.com/ru/post/335756/
По-моему там есть пример.
По сути, assign(to:) - это прямая передача публикуемого значения другому "издателю" Publisher $currentWeather и никакой reference cycle не возникает.
Верно. Вы можете использовать вместо этого
Или использовать новый в iOS 14 метод https://developer.apple.com/documentation/combine/fail/assign(to:)
код стал еще проще.
Пожалуй, действительно не стоит обсуждать эффективное хранение структур
structтем более в Standard Library.В документации по Swift вовсе не сказано напрямую, что оптимизация хранения структур
struct типамассивовArray, словарейDictionaryи строкStringпредполагает использование "кучи" (heap), там лишь сказано, что используется оптимизация для уменьшения затрат на копирование. Вместо того, чтобы делать копию немедленно, эти коллекции совместно используют память, в которой хранятся элементы, между исходным экземпляром и любыми копиями. Если одна из копий коллекции изменяется, элементы копируются непосредственно перед изменением.Так что Apple оставляет за собой право, как она будет оптимизировать хранение структур
struct, может и изменить это в любой момент времени.Для нас важно лишь то, что в нашем коде ВСЕГДА у структуры
structбудет такое поведение при изменении, как если бы копия была создана немедленно.По большому счету структуры
structявляются "неизменяемыми" (immutable) структурами данных в отличие от классовclass.Именно на основе того, что при любом изменении структуры
structмы всегда имеем её новый экземпляр,и строится функциональное программирование.Это особенно видно в новом фреймворке SwiftUI, в котором архитектура строится на основе
MVVM, гдеView- всегда структурыstruct, аViewModels- классыclass. Программирование в SwiftUI - это функциональное программирование.Вы сами задаете интервал обновления.
А в fetch() уже работает @Published, а точнее CurrentValueSubject<Set, Never>([]), но это близко к @Published, и это воздействует на View SwiftUI.
Лично меня поразило быстродействие связки Combine+ SwiftUI в задаче выборки данных о фильмах и их кинопостерах, что относится к ресурсо- затратным задачам. В том примере, который приведен в этой статье, при переходе от одной коллекции фильмов ( от тех, которые сейчас на экране, к популярным), выборка данных происходит столь быстро, что даже нет необходимости в экране «Loading...». «Сто лет» занимаюсь этими задачами и Combine+ SwiftUI преподнесли мне приятный сюрприз.
Problem Solving with Combine Swift
Я конечно, не замеряла, но быстродействие очень хорошее.
Те, кто специально этим занимался отмечают существенное быстродействие по сравнению с UIKit.
Что касается навигации, то есть одно очень хорошее решение «Recreation of calculator-checklist project in SwiftUI», где очень просто воссоздается CustomSegue:
Arrayявляются структурамиstructиValueТИПАМИ. В SwiftValueТИПЫ хранятся в стеке.Каждый поток имеет свое собственное пространство стека, поэтому никакой другой поток не сможет напрямую получить доступ к вашему
ValueТИПУ. Следовательно, нет условий для гонки, блокировок, взаимных блокировок или каких-то других сложностей, связанных с синхронизацией потоков.Если массив Array — очень большой, то для них использует механизм «Copy-on-Write».
Когда вы изменяете (например, добавляете append элементы) массив
Array, он использует стандартную библиотечную функцию «isUniquelyReferenced», чтобы увидеть, есть ли какие-либо другие массивы, указывающие на буфер, к которому он собирается добавить. Если они есть, он делает копию, и копия становится ее новым резервным хранилищем. Это называется «Copy-on-Write».map,flatMap,filter, то увидите, что именно так они и реализованы, никакой магии тут нет.Но если вы находитесь в пределах императивного кода, то вам самому нужно все время контролировать себя, не делаете ли вы каких-то изменений «по месту».
Использование же функционального кода вам точно гарантирует «неизменяемость» за счет создания новых массивов ( или последовательностей или еще чего-нибудь) в функциях «высшего порядка».
ApplemapдляSequenceсейчас действительно не имеет@escaping(хотя раньше имела):func map(_ transform: (Element) throws -> T) rethrows -> [T]
перевыбрасывает (Теперь map
rethrows) ошибку.Но во всех постах очень известного сайта по функциональному программированию на
Swiftpointfree.com во всехmapпередtransformстоит@escaping.Но, похоже, вы правы и наличие
@escapingсейчас является артефактом с прошлой версии.Исправим.
— удаляется элемент с индексом 2, то есть 8
— удаляется элемент с индексом 5, то есть 0
— удаляется элемент с индексом 0, то есть 6
— удаляется элемент с индексом 6, то есть 7
И остается [22, 14, 16, 9]
Было восемь элементов, удалили четыре — осталось четыре
Считает все правильно — посмотрите на Playground.
@escaping— асинхронное выполнение кода. Если вы используете замыкание асинхронно с помощьюDispatchQueгу, то очередьqueueбудет удерживать ваше замыкание в памяти для того, чтобы использовать его в будущем. В этом случае вы не можете точно сказать, когда замыкание будет выполнено. ВсеGenericmapимеют@escapingзамыкание, так как заранее неизвестно в какой среде вы будете его использовать.