Profiling apps using Instruments
‼️ Apple выпустили хороший курс по работе с инструментами профилирования.
💡 Весь курс направлен на поиск и устранение зависаний, анализ синхронных и асинхронных работ, разгрузку главного потока.
Сам курс рассчитан на 1 час 35 минут.
Если еще не смотрели - то сейчас самое время🔍
Сам курс рассчитан на 1 час 35 минут.
Если еще не смотрели - то сейчас самое время
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍4
Documenting your code with DocC
🖥 DocC — это компилятор документации от Apple, который преобразует текст на основе Markdown в богатую документацию для Swift-фреймворков и пакетов.
➡️ Для добавления документации используйте тройные слэши вместо двойных. Это позволяет компилятору DocC извлекать информацию непосредственно из исходного кода.
➡️ Документация может включать описание параметров, возвращаемых значений и ошибок с использованием ключевых слов 🔗 Для упоминания других типов в документации используйте двойные обратные кавычки, что позволяет DocC создавать ссылки на соответствующие элементы документации.
Parameters
, Returns
и Throws.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Rules of Structured Concurrency
⚙️ Структурированные задачи (например,
⚠️ Существуют три основных правила:
- правило завершения группы
- правило отмены группы
- правило распространения ошибок, которые применяются только к структурированным задачам.
⏩ Структурированные задачи лучше использовать для выполнения нескольких параллельных операций, в то время как неструктурированные задачи подходят для выполнения работы независимо от текущего контекста.
⏩ Неструктурированные задачи наследуют приоритет и локальные значения задачи, тогда как структурированные задачи не наследуют изолированность акторов, что позволяет им работать параллельно.
async let
и task group
) управляют дочерними задачами, в то время как неструктурированные задачи (например, Task
и Task.detached
) создают независимые деревья задач без родительских связей.- правило завершения группы
- правило отмены группы
- правило распространения ошибок, которые применяются только к структурированным задачам.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥1
NSAttributedString: Formatting Rich Text in Swift
⏩
✔️ Для создания изменяемой строки используется
➡️ Можно изменять цвет текста, шрифт, добавлять зачеркивание и подчеркивание, а также создавать кликабельные ссылки и настраивать стили абзацев для выравнивания и интервалов.
❗️
💡 Рекомендуется кэшировать атрибутированные строки и использовать
NSAttributedString
— это класс, позволяющий добавлять атрибуты, такие как цвет и шрифт, к определенным диапазонам текста, создавая богатый текст с различными стилями в одном строковом объекте.NSMutableAttributedString
, что позволяет добавлять атрибуты к поддиапазонам текста, например, изменять цвет или шрифт отдельных слов.NSAttributedString
можно использовать с UIKit
через свойства attributedText в UILabel
и UITextView
, а также с SwiftUI
, начиная с iOS 15, с помощью нового типа AttributedString
.NSMutableAttributedString
только при необходимости модификации текста для повышения производительности.let attributedString = NSMutableAttributedString(string: "A text with a background color.")
// Applying foreground color to "text"
attributedString.addAttributes(
[.foregroundColor : UIColor.red],
range: NSRange(location: 2, length: 4)
)
// Applying background color to "text with a background"
attributedString.addAttributes(
[.backgroundColor: UIColor.yellow],
range: NSRange(location: 2, length: 22)
)
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🤔1
Rendering quadratic Bézier curves with Metal
💡 Интересная статья про то, как начали использовать упрощенный метода рендеринга квадратичных кривых Безье с помощью Metal. Данный метода основан на алгоритме Kokojima. Он включает в себя создание трафаретного буфера и шейдинга.
⏩ Процесс включает создание треугольного вентиля вокруг начальной точки, рендеринг кривых с использованием контрольных точек и применение шейдера для отсеивания пикселей вне кривой.
⏩ Метод поддерживает как выпуклые, так и вогнутые кривые, что позволяет эффективно обрабатывать самопересекающиеся сегменты.
⏩ Для сглаживания краев используют встроенную многообразную выборку Metal, что упрощает процесс по сравнению с более сложными решениями.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2
iOS Performance tips you probably didn't know (from an ex-Apple engineer)
Крутая статья трюки оптимизации в приложении. Вот краткий обзор.
⚠️
Он может потреблять значительное количество памяти, особенно если он не монохромный. Для уменьшения использования памяти рекомендуется обнулять текст меток в ячейках
➡️ Использование очередей:
Начинайте с последовательных очередей для выполнения задач, а параллельные очереди используйте только в случае необходимости. Это поможет избежать создания лишних потоков и улучшит производительность.
ℹ️ Симуляция предупреждений о памяти:
Некоторые системные компоненты освобождают память только при получении предупреждения о низкой памяти. Вы можете симулировать это в эмуляторе iOS или на тестовом устройстве.
🛡 Избегайте семафоров;
Использование dispatch_semaphore_t для ожидания асинхронной работы может привести к инверсии приоритетов. Вместо этого лучше использовать синхронные прокси с XPC.
✏️ Проблемы с тегами UIView:
Использование тегов в UIView может негативно сказаться на производительности из-за дополнительных затрат на поиск. Лучше избегать их в производительном коде.
Крутая статья трюки оптимизации в приложении. Вот краткий обзор.
UILabel
дорого стоит:Он может потреблять значительное количество памяти, особенно если он не монохромный. Для уменьшения использования памяти рекомендуется обнулять текст меток в ячейках
UITableView/UICollectionView
, когда они скрыты.Начинайте с последовательных очередей для выполнения задач, а параллельные очереди используйте только в случае необходимости. Это поможет избежать создания лишних потоков и улучшит производительность.
Некоторые системные компоненты освобождают память только при получении предупреждения о низкой памяти. Вы можете симулировать это в эмуляторе iOS или на тестовом устройстве.
Использование dispatch_semaphore_t для ожидания асинхронной работы может привести к инверсии приоритетов. Вместо этого лучше использовать синхронные прокси с XPC.
Использование тегов в UIView может негативно сказаться на производительности из-за дополнительных затрат на поиск. Лучше избегать их в производительном коде.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6😱3❤2👍2
How to inspect .ipa files and secure your iOS app from common mistakes
ℹ️ Интересная статья для тех, кто не знал, что можно достать путем анализа .ipa файла приложения.
🤫 Автор выделяет три основных правила для обеспечения базовой безопасности информации.
➡️ Правило 1: Защита данных
Не добавляйте чувствительные данные в
➡️ Правило 2: Избегайте тестовых данных
Не включайте данные для разработки или тестирования в целевые приложения, чтобы избежать утечек информации.
➡️ Правило 3: Защита строковых литералов
Не храните чувствительные ключи и секреты в строковых литералах; используйте методы обфускации или шифрования - через утилиту
🔍 Для более глубокого анализа используйте специальные инструменты, такие как
Не добавляйте чувствительные данные в
Info.plist
, так как этот файл не зашифрован и доступен для чтения.Не включайте данные для разработки или тестирования в целевые приложения, чтобы избежать утечек информации.
Не храните чувствительные ключи и секреты в строковых литералах; используйте методы обфускации или шифрования - через утилиту
strings
можно много чего увидеть.IDA pro
или Hopper
, которые позволяют дизасемблировать приложение и изучить внутренние структуры и не только.Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Swift Reduce: Combining elements into a single value
💡 Метод
⚠️ Метод
➡️ Хотя
reduce
в Swift позволяет объединять элементы коллекции в одно значение, что делает его полезным для преобразования массивов в словари или суммирования чисел.reduce
имеет сложность O(n)
и может использоваться с вариантом reduce(into:)
, который более эффективен, избегая копирования аккумулятора на каждой итерации.reduce
делает код более элегантным, для сложной логики может быть лучше использовать обычные циклы, чтобы повысить читаемость.let animals = ["Dog", "Cat", "Dog", "Bird"]
let counts = animals.reduce(into: [:]) { result, animal in
result[animal, default: 0] += 1
}
// counts == ["Dog": 2, "Cat": 1, "Bird": 1]
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Modern URL construction in Swift
➡️ Swift 5.9 представил макросы, которые позволяют компилировать и валидировать статические URL-строки, улучшая безопасность кода.
➡️ С введением новых API в iOS 16, можно легко создавать динамические URL без опциональных значений, используя методы
✏️ Современные API для создания URL упрощают код, уменьшают вероятность ошибок и позволяют работать с URL более структурированно.
appending.
@freestanding(expression)
public macro staticURL(_ value: StaticString) -> URL = #externalMacro(
module: "StaticURLMacros",
type: "StaticURLMacro"
)
public struct StaticURLMacro: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> ExprSyntax {
// Verify that a string literal was passed, and extract
// the first segment. We can be sure that only one
// segment exists, since we're only accepting static
// strings (which cannot have any dynamic components):
guard let argument = node.arguments.first?.expression,
let literal = argument.as(StringLiteralExprSyntax.self),
case .stringSegment(let segment) = literal.segments.first
else {
throw StaticURLMacroError.notAStringLiteral
}
// Verify that the passed string is indeed a valid URL:
guard URL(string: segment.content.text) != nil else {
throw StaticURLMacroError.invalidURL
}
// Generate the code required to construct a URL value
// for the passed string at runtime:
return "Foundation.URL(string: \(argument))!"
}
}
let url = #staticURL("https://swiftbysundell.com")
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
libdispatch efficiency tips
👀 Нашел тут довольно старую, но актуальную подборку советов по работе с GCD. Вот некоторые из них:
➡️ Создавайте несколько долгоживущих и четко определенных очередей, чтобы использовать их как контексты выполнения в вашем приложении. Обычно достаточно 3-4 очередей.
➡️ Начинайте с серийной обработки и только при обнаружении узких мест переходите к конкурентности, тщательно измеряя производительность.
➡️ Глобальные очереди могут привести к взрыву потоков и неэффективности. Используйте свои собственные очереди для лучшей производительности.
➡️ Некоторые классы и библиотеки лучше проектировать как синхронные API, чтобы избежать проблем с производительностью и сложностью асинхронного кода.
➡️ Проводите реальные тесты производительности вашего продукта, чтобы убедиться, что изменения действительно улучшают скорость, а не ухудшают.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
This media is not supported in your browser
VIEW IN TELEGRAM
Пятничный Vibe-coding
👀 Решил попробовать этот ваш вайб кодинг
Выглядит, конечно, как магия - тут тебе и дизайнер и разработчик в одном лице. Главная задача - хорошо и понятно написать промпт.
Похоже на то, что в ближайшее время мы уже будем меньше писать кода сами, а больше времени уделять ревью и отладке - местами, код, который получился после генерации, похож на код джуна🥸
Да и видно, что дизайну он соответствует не полностью (хотя он сам его придумал🫠 ).
Но это намного лучше и быстрее, чем писать все изначально с 0🔥
P.S. Я использовал Cursor и плагин для фигмы
Выглядит, конечно, как магия - тут тебе и дизайнер и разработчик в одном лице. Главная задача - хорошо и понятно написать промпт.
Похоже на то, что в ближайшее время мы уже будем меньше писать кода сами, а больше времени уделять ревью и отладке - местами, код, который получился после генерации, похож на код джуна
Да и видно, что дизайну он соответствует не полностью (хотя он сам его придумал
Но это намного лучше и быстрее, чем писать все изначально с 0
P.S. Я использовал Cursor и плагин для фигмы
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥3
Пробовали Vibe-coding
Anonymous Poll
29%
Да, Крутая штука
14%
Да, но больше не буду
31%
Нет
26%
Что это вообще такое?
Building Type‑Safe, High‑Performance SwiftData / Core Data Models
🔍 В статье приводятся советы, как сделать модели для
Вот некоторые моменты:
➡️ В отличие от
➡️ Использование библиотеки NonEmpty позволяет гарантировать, что строка не пустая, что улучшает семантику и предотвращает ошибки на этапе компиляции.
➡️ Для многовариантных выборок рекомендуется использовать битовые операции для хранения данных, что значительно повышает производительность запросов в
➡️
CoreData
/SwiftData
типо-безопасными и эффективными.Вот некоторые моменты:
SwiftData
, CoreData
требует использования NSNumber
для опциональных числовых свойств, что нарушает стиль Swift
. Решение включает использование вычисляемых свойств для обеспечения безопасности типов.SQLite
.SwiftData
требует явного определения инициализаторов, что помогает предотвратить ошибки и обеспечивает строгий порядок создания моделей.extension DataContent {
// Public array interface
public var optionSelections: [Int] {
get { optionIDsNumber.toArray() }
set { optionIDsNumber = optionIDsToInt64(optionIDs: newValue) }
}
// Stored as a bitmask
private var optionIDsNumber: Int64
}
func optionIDsToInt64(optionIDs: [Int]) -> Int64 {
var result: Int64 = 0
for id in optionIDs where id >= 0 && id <= 63 {
// Set the bit corresponding to each ID
result |= (1 << id)
}
return result
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤2
How a Single Line Of Code Could Brick Your iPhone
🔍 Крутая статья про то, к чему приводит любознательность и понимание механизмов работы различных компонентов.
🔔 Уязвимость в
Вот эта строка:
🆒
🗓 Первоначальный отчет о проблеме был отправлен в Apple 26 июня 2024 года, а уязвимость была исправлена в iOS 18.3 с присвоением CVE-2025-24091.
💵 За это автор получил вознаграждение в размере 17.5 к $.
✔️ Теперь для отправки чувствительных уведомлений Darwin требуется наличие ограниченных прав, что предотвращает несанкционированные действия со стороны приложений.
Darwin notifications
позволяет любому процессу на iOS отправлять уведомления без специальных привилегий.Вот эта строка:
notify_post("com.apple.MobileSync.BackupAgent.RestoreStarted")
+ виджет и fatalError()
окирпичивали телефон.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍1
Swift Error Handling Done Right: Overcoming the Objective-C Error Legacy
👀 Описываешь ошибки в коде, которые конформят
Ну было, да?🤦♂️
Если ответ положительный, то вам нужно прочитать эту статью.
Коротко:
✔️
💡 Автор предлагает свой протокол
Error
протокол, и ожидаешь получить внятное объяснение при выбрасывании, но вместо этого: "The operation couldn't be completed. (YourApp.YourError error 0.)"
enum NetworkError: Error {
case noConnectionToServer
case parsingFailed
var localizedDescription: String {
switch self {
case .noConnectionToServer:
return "No connection to the server."
case .parsingFailed:
return "Data parsing failed."
}
}
}
// Using the error
do {
throw NetworkError.noConnectionToServer
} catch {
print("Error message: \(error.localizedDescription)")
// Expected: "No connection to the server."
// Actual: "The operation couldn't be completed. (AppName.NetworkError error 0.)"
}
Ну было, да?
Если ответ положительный, то вам нужно прочитать эту статью.
Коротко:
Swift
предлагает использовать протокол LocalizedError
для обработки ошибок, но он имеет недостатки, такие как необязательные свойства и неясные названия.Throwable
, который требует единственного обязательного свойства userFriendlyMessage
, что упрощает создание понятных сообщений об ошибках.Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2
Руководство по использованию unsafe в Swift
ℹ️ В
⚠️ Использование небезопасных механизмов оправдано при взаимодействии с C API, для оптимизации производительности, низкоуровневого программирования и работы с Objective-C.
⚙️ Важно минимизировать область использования
🔴 Преимущества использования
Swift
существуют различные способы работы с небезопасными операциями, включая прямое использование указателей и встроенные обёртки, такие как UnsafePointer
и UnsafeMutablePointer.
unsafe
, применять конструкции withUnsafe
для безопасного доступа к указателям и тщательно документировать код для предотвращения утечек памяти.unsafe
включают производительность и гибкость, однако риски связаны с утечками памяти и сложностью поддержки кода.import Foundation
let count = 4
// Выделяем память для 4 байтов
let rawPointer = UnsafeMutableRawPointer.allocate(byteCount: count, alignment: MemoryLayout<UInt8>.alignment)
// Инициализируем память
for i in 0..<count {
rawPointer.storeBytes(of: UInt8(i), toByteOffset: i, as: UInt8.self)
}
// Чтение данных через UnsafeRawPointer
let immutableRawPointer = UnsafeRawPointer(rawPointer)
for i in 0..<count {
let byte = immutableRawPointer.load(fromByteOffset: i, as: UInt8.self)
print("Байт \(i): \(byte)")
}
// Освобождаем память
rawPointer.deallocate()
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Bridging interfaces with the Adapter pattern in Swift
➡️ Паттерн адаптер позволяет интегрировать сторонние API или устаревший код, сохраняя при этом чистоту архитектуры приложения.
✏️ В примере показано, как адаптировать интерфейс стороннего SDK с использованием протокола
💡 Использование адаптера помогает сохранить инкапсуляцию и чистое разделение между доменами, что делает код более устойчивым к изменениям.
SearchService
, чтобы обеспечить совместимость с существующим кодом.protocol SearchService {
func search(query: String) async throws -> [SearchResult]
}
class ThirdPartySearch {
func runSearch(term: String, completion: @escaping ([Any]) -> Void) {
// ...
}
}
class ThirdPartySearchAdapter: SearchService {
private let thirdPartySearch = ThirdPartySearch()
func search(query: String) async throws -> [SearchResult] {
try await withCheckedThrowingContinuation { continuation in
thirdPartySearch.runSearch(term: query) { rawResults in
let results = rawResults.compactMap { $0 as? SearchResult }
continuation.resume(returning: results)
}
}
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Custom subscripts in Swift explained with code examples
➡️
⚙️
можно определить, как методы, и они могут принимать несколько параметров, что позволяет улучшить читаемость кода.
ℹ️ Подписки могут быть как только для чтения, так и для записи, что позволяет не только получать, но и устанавливать значения в коллекциях.
➡️ Статические подписки позволяют обращаться к элементам без необходимости раскрывать детали экземпляра, что улучшает инкапсуляцию.
➡️
Subscript в Swift
позволяют создавать короткие пути к элементам коллекций, что упрощает доступ к данным в классах, структурах и перечислениях.Custom subscripts
можно определить, как методы, и они могут принимать несколько параметров, что позволяет улучшить читаемость кода.
Subscripts
могут принимать необязательные параметры, что добавляет функциональность, например, для получения изображений по базовому URL.extension ImageCache {
subscript(url: URL) -> UIImage? {
get {
imageStore[url]
}
set {
imageStore[url] = newValue
}
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4👎1
Regular Expressions in Swift
⚙️ В Swift регулярные выражения реализованы через класс
⚠️ Однако стоит помнить, что чрезмерное использование регулярных выражений в больших текстах может негативно сказаться на производительности приложения. С выходом Swift 5.7 появился более современный и удобный инструмент -
💡 В статье подробно рассмотрены основы работы с
NSRegularExpression
из Foundation
, который позволяет создавать шаблоны и искать совпадения в строках. Для удобства можно расширить этот класс, чтобы упростить создание и проверку выражений, например, добавить метод matches()
, который проверяет наличие совпадений в строке. Swift Regex
с лаконичным синтаксисом и билдерами регулярных выражений, который значительно упрощает работу и повышает читаемость кода по сравнению с NSRegularExpression
NSRegularExpression
, примеры использования, а также преимущества новых подходов Swift Regex
с множеством практических примеров. Рекомендуем к прочтению всем, кто хочет глубже понять регулярные выражения в Swift и писать более эффективный и чистый код.// matching a url
let link = Reference(URL.self)
let linkRB = Regex {Capture (as:link){.url()}}
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5