Swift runloop что это
RunLoop Swift: что это такое, для чего нужен?
В системе АйОС имеется так называемая многослойность, информации о которой достаточно мало, вследствие чего многим пользователям приходится обращаться к различным источникам для получения полноценной информации.
Определенные программы должны быть установлены в обязательном порядке для полноценного использования определенных функциональных возможностей устройства. Одной из них и является RunLoop. Что это и с какой целью применяется на устройстве?
Все, что необходимо знать о работе с данной утилитой
Несмотря на то, что RunLoop не работает с полноценными потоками, а используется только для улучшения и упрощения выполнения определенных операций, стоит сказать о том, что такая утилита является необходимой, вследствие чего стоит рассмотреть ее работу и особенности.
RunLoop представляет собой определенного рода бесконечный цикл, который используется на том или ином устройстве для обработки и проведения координации всех событий, которые поступают на установленный вход.
В том случае, если поток идет нескончаемым образом, приложение может влиять на скорость обработки прочих запросов, однако такое происходит достаточно редко. К тому же, у каждого отдельного потока имеется свой определенный RunLoop, который является ассоциативным.
Для главного потока запуск происходит в автоматическом режиме, а в том случае, если создаются дополнительные потоки, для них открываются новые направления обработки для того, чтобы процесс осуществлялся в наиболее короткие сроки.
Так, например, все системные события запускаются и в обязательном порядке детально обрабатываются в главном потоке, где происходит их переформирование, можно осуществлять управление и вносить определенные корректировки для получения необходимого результата.
По сути, программа предполагает процесс отличия обычной мобильной программы от интерактивного приложения, которое требует больше возможностей от устройства и имеет большое количество требований к работе системы.
Она работает в постоянном режиме и способствует повышению качества работы различных файлов.
IOS Run Loop: Что? Когда? Зачем?
Run Loop (цикл исполнения) является механизмом, который позволяет потокам обрабатывать события (events) бесконечно в любое время.
Run Loop представляет из себя объект, который управляет событиями и сообщениями, обрабатывает их, и предоставляет функцию точки входа для выполнения логики события.
В OSX/iOS у нас уже есть реализация этого механизма в виде NSRunLoop и CFRunLoopRef. CFRunLoopRef является частью фреймворка CoreFoundation. Он предоставляет API для функций на чистом C, которое является потокобезопасным.
NSRunLoop — это обертка, берущая за основу CFRunLoopRef, которая предоставляет объектно-ориентированное API, но это API не является потокобезопасным.
В системе по умолчанию предусмотрено пять режимов:
kCFRunLoopDefaultMode: дефолтный для вашего приложения режим, обычно в этом режиме выполняется основной (main) поток.
UITrackingRunLoopMode: режим отслеживания интерфейса, используемый ScrollView для отслеживания касаний и слайдов, чтобы гарантировать, что интерфейс не зависит от других режимов при слайдинге.
UIInitializationRunLoopMode: первый режим, в который приложение входит при запуске, он не будет больше использоваться после завершения запуска.
GSEventReceiveRunLoopMode: внутренний режим для приема системных событий, обычно не используется.
kCFRunLoopCommonModes: это режим-заполнитель, не имеющий практического значения.
Четыре функции цикла исполнения:
Принимать вводимые пользователем данные, не прерывая выполнения программы.
Решать, когда события должны обрабатываться программой.
Экономить время процессора
Цикл исполнения основного потока запускается по умолчанию. В iOS-приложении после запуска функция main() будет следующей:
Ключевым моментом является функция UIApplicationMain(). Этот метод устанавливает объект NSRunLoop для основного потока (main thread).
Это объясняет, почему наше приложение может находиться в состоянии сна, когда мы с ним не взаимодействуем (никакие действия не выполняются) и в то же время немедленно реагировать, когда какое-либо действие наконец совершается.
Для других потоков цикл исполнения по умолчанию не запускается. Если вам нужно больше интерактивности с потоками, вы можете вручную настроить и запустить его. Если поток выполняет только долгосрочную заранее заданную задачу, то в этом нет необходимости. В любом потоке Cocoa-программы вы можете сделать следующее, чтобы запустить цикл исполнения в текущем потоке.
Цикл исполнения (run loop) — это цикл обработки событий, который используется для непрерывного мониторинга и обработки входящих событий и назначения их соответствующим таргетам для дальнейшей обработки.
NSRunLoop — более умная модель обработки сообщений. Он умело абстрагировал и инкапсулировал процесс обработки сообщений, чтобы вам не приходилось иметь дело с очень тривиальной и низкоуровневой конкретикой обработки сообщений. Каждое сообщение упаковано в источник ввода (input source) или источник таймера (timer source). Использование цикла исполнения позволяет вашему потоку работать, когда есть работа, и переходить в спящий режим, когда работы нет, что может значительно сэкономить системные ресурсы.
Изображение взято со stackoverflow. Ссылка ниже.
Когда следует использовать цикл исполнения?
Cocoa предоставляет код для запуска основного цикла (main loop) программы и автоматического запуска цикла исполнения. Метод запуска UIApplication в программе IOS (или NSApplication в Mac OS X) используется как часть этапа запуска программы. Он запустит основной цикл программы, когда будет завершен ее запуск.
Для вспомогательных же потоков вам самим необходимо определить, нужны ли им циклы исполнения. Если нужны, то вам придется настроить и запустить их самостоятельно. По умолчанию вам не рекомендуется запускать цикл исполнения для потока ни при каких обстоятельствах. Например, когда вы используете потоки для обработки заранее определенной длительной задачи, вам следует избегать запуска цикла исполнения. Запуск цикла исполнения оправдан только если вы хотите активно взаимодействовать с потокам, например:
использовать кастомные порты или источники ввода для коммуникации с другими потоками
использовать потоковые таймеры (threaded timers)
использовать метод Cocoa с любым performSelector’ом
перевести поток в режим периодической работы
NSRunLoop класс в Cocoa не потокобезопасен
Мы не можем управлять объектом цикла исполнения одного потока в другом потоке — это может привести к неожиданным результатам. К счастью, opaque класс CFRunLoopRef в CoreFundation является потокобезопасным, что позволяет миксовать между собой типы циклов исполнения. Класс NSRunLoop в Cocoa может быть реализован с помощью методов инстанса:
Остается только выберать соответствующий класс CFRunLoopRef для обеспечения потокобезопасности.
Управление циклом исполнения не является полностью автоматическим
Нам все еще нужно писать в потоке код, запускающий цикл исполнения в подходящее время, и должным образом реагировать на события, конечно, если цикл исполнения необходим в этом потоке. Более того, нам также нужно использовать операторы while/for, чтобы сделать цикл исполнения бесконечным. Следующий код успешно запускает цикл исполнения:
Цикл исполнения также отвечает за создание и выпуск autorelease пула.
Материал подготовлен в рамках курса «iOS Developer. Professional». Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем курса — приглашаем на день открытых дверей онлайн. Регистрация здесь.
Про многопоточность 1. Thread
Привет. Поймал себя на мысли, что слишком часто приходится обращаться к различным источникам в поисках информации про многопоточность в iOS. Такое себе удовольствие, поэтому собрал все самое полезное и не очень в ряд статей, посвященных многопоточности, ее особенностям и подкапотной жизни. Завариваем чаек и погнали.
Про многопоточность 1. Thread
Про многопоточность 3. NSOperation (coming soon)
Про многопоточность 4. Железяки (coming soon)
Threads
Все операции, выполняемые в мобильном приложении, требуют некоторых ресурсов и имеют время выполнения. Эти операции by default выполняются поочередно в главном потоке.
Главным потоком называется поток, в котором стартует приложение. Обработка событий связанных со взаимодействием с UI происходит на главном потоке (такой операцией может быть обработка тапа по экрану, нажатия на клавишу клавиатуры, движение мыши и тд). Помимо этого, любая операция, написанная нами, будь то выполнение алгоритма, запрос в сеть или обращение к базе данных так же будет выполняться поочередно на главном потоке, что может негативно сказываться на отклике UI. Здесь к нам на помощь приходит многопоточность — возможность выполнять операции параллельно (одновременно) на разных потоках.
Run Loop
И начнем мы, нет, не с потоков, а с части, тесно связанной с их работой, а именно Run Loop. Документация гласит:
A run loop is an event processing loop that you use to schedule work and coordinate the receipt of incoming events. The purpose of a run loop is to keep your thread busy when there is work to do and put your thread to sleep when there is none
Run Loop — своего рода бесконечный цикл, предназначенный для обработки и координации всех событий, поступающих к нему на вход. В первую очередь стоит отметить, что у каждого потока есть свой ассоциированный Run Loop. Run Loop для главного потока приложение (UIApplication) инициализирует и стартует автоматически, в то время как для созданных потоков запускать и конфигурировать Run Loop необходимо самостоятельно.
Зачем же нужен этот ваш ранлуп? К примеру, Run Loop главного потока отлавливает все системные события и запускает их обработку на главном потоке, будь то нажатия на клавиши клавиатуры, если это macOS, или тап по экрану iOS устройства. Также Run Loop умеет управлять своим потоком: будить для выполнения некоторой работы и переводить в спячку после ее выполнения.
По большому счету, Run Loop — это то, что отличает интерактивное мобильное приложение от обычной программы. Когда Run Loop получает сообщение о событии, он запускает обработчик, ассоциированный с этим событием на своем потоке, а после выполнения усыпляет поток до следующего события, именно таким образом приложение узнает о происходящих интерактивных событиях. Разберемся, какие же события умеет обрабатывать Run Loop:
Существует несколько источников события:
Input sources — различные источники ввода (мышь, клавиатура, тачскрин и тп), кастомные источники (необходимы для передачи сообщений между потоками), а так же вызов performSelector:onThread: (метод, необходимый для вызова события по селектору на определенном потоке)
Timer sources — все таймеры в приложении всегда обрабатываются ранлупом
Как уже говорилось ранее, Run Loop’ом главного потока управляет приложение, в то время, как мы сами управляем Run Loop’ом созданных нами потоков, таким образом мы можем явно указать, какие источники ввода должен обрабатывать Run Loop. Рассмотрим режимы работы Run Loop:
NSDefaultRunLoopMode — режим по умолчанию, который отслеживает все основные события
NSModalPanelRunLoopMode — режим, отслеживающий события в модальных окнах (используется только в macOS)
NSEventTrackingRunLoopMode — режим, который отслеживает системные события связанные с UI (скроллинг, тап по экрану, движение мыши, нажатия на клавиатуре и тп.)
В качестве примера использования режимов Run Loop может быть распространенная проблема, связанная с некорректной работой таймера. Давайте разбираться:
pthread
Рассмотрим аргументы данной функции:
! — указатель на существующий pthread
? — указатель на атрибуты потока, которые позволяют нам настроить поток ( pthread_attr(3) )
_: UnsafeMutableRawPointer? — указатель на аргументы, которые мы хотим передать в функцию
Рассмотрим пример создания pthread :
Поток начнет свое выполнение сразу после создания ( pthread_create ).
Thread
Рассмотрим пример создания потока Thread :
У Thread есть альтернативный способ создания, с использованием Target-Action паттерна:
Quality of service
Существует 5 типов QOS:
Рассмотрим пример использования QOS:
Во фреймворке Foundation так же, как и в pthread API есть возможность приоритезировать задачи с помощью QOS.
Рассмотрим использование QOS в Thread :
Синхронизация
При работе с многопоточностью, часто встает вопрос синхронизации. Существуют ситуации, в которых несколько потоков имеют одновременный доступ к ресурсу, например Thread1 читает ресурс в то время, как Thread2 изменяет его, что приводит к коллизии.
Во избежание таких ситуации существует несколько способов синхронизации, такие как mutex и semaphore. Синхронизация позволяет обеспечить безопасный доступ одного или нескольких потоков к ресурсу.
Mutex
Mutex — примитив синхронизации, позволяющий захватить ресурс. Подразумевается, что как только поток обратиться к ресурсу, захваченному мьютексом, никакой другой поток не сможет с ним взаимодействовать до тех пор, пока текущий поток не освободит этот ресурс
Рассмотрим пример использования pthread mutex:
Стоит отметить, что mutex работает по принципу FIFO, то есть потоки будут захватывать ресурс по освобождению в том порядке, в котором данные потоки обратились к ресурсу.
NSLock
Рассмотрим пример использования NSLock :
Reqursive mutex
Reqursive mutex — разновидность базового mutex, которая позволяет потоку захватывать ресурс множество раз до тех пор, пока он не освободит его. Ядро операционной системы сохраняет след потока, который захватил ресурс и позволяет ему захватывать ресурс повторно. Рекурсивный мьютекс считает количество блокировок и разблокировок, таким образом ресурс будет захвачен до тех пор, пока их количество не станет равно друг другу. Чаще всего используется в рекурсивных функциях.
Рассмотрим пример использования Reqursive mutex:
Если бы в данном примере использовался обычный mutex, поток бы бесконечно ожидал, пока он же сам не освободит ресурс.
NSRecursiveLock
Рассмотрим пример использования NSRecursiveLock :
Condition
Рассмотрим пример использования condition:
NSCondition
Рассмотрим пример использования NSCondition :
Read Write Lock
Read Write Lock — примитив синхронизации, который предоставляет потоку доступ к ресурсу на чтение, в это время закрывая возможность записи в ресурс из других потоков.
Необходимость использовать rwlock появляется тогда, когда много потоков читают данные, и только один поток их пишет (Reader-writers problem). На первый взгляд кажется, что данную проблему можно легко решить простым mutex, однако этот подход будет требовать больше ресурсов, нежели простой rwlock, так как фактически нет необходимости блокировать доступ к ресурсу полностью. rwlock имеет достаточно простое API:
Рассмотри пример практического использования rwlock:
Существует только unix вариация rwlock, во фреймворке Foundation нет альтернативы. В следующей статье мы рассмотрим альтернативы из более высокоуровневых библиотек.
Spin Lock
Spin lock — наиболее быстродействующий, но в то же время энергозатратный и ресурсотребователный mutex. Быстродействие достигается за счет непрерывного опрашивания, освобожден ресурс в данный момент времени или нет.
Рекомендуется использовать spin lock лишь в редких случаях, когда к ресурсу обращается небольшое количество потоков непродолжительное время.
Unfair Lock
Unfair lock (iOS 10+) — примитив многопоточности, позволяющий наиболее эффективно захватывать ресурс. По большому счету, unfair lock является более производительной заменой spin lock. Производительность достигается путем максимального сокращения возможных context switch.
Context switch — процесс переключения между потоками. Для того, чтобы переключаться между потоками, необходимо прекратить работу на текущем потоке, сохранив при этом состояние и всю необходимую информацию, а далее восстановить и загрузить состояние задачи, к выполнению которой переходит процессор. Является энергозатратной и ресурсотребовательной операцией
Вспоминаем, что обычный mutex работает по принципу FIFO, в то время, как unfair lock отдаст предпочтение тому потоку, который чаще обращается к ресурсу, таким образом и достигается сокращение context switch. Имеет достаточно простое API:
Проблемы
Многопоточность предназначена для решения проблем, но как и любые другие технологии может порождать новые. В большинстве случаев проблемы связанны с доступом к ресурсам. Самые распространенные из них:
Deadlock — ситуация, в которой поток бесконечно ожидает доступ к ресурсу, который никогда не будет освобожден
Priority inversion — ситуация, в которой высокоприоритетная задача ожидает выполнения низкоприоритетной задачи.
Race condition — ситуация, в которой ожидаемый порядок выполнения операций становится непредсказуемым, в результате чего страдает закладываемая логика
В данной статье мы рассмотрим только Deadlock, так как остальные проблемы стоит решать используя более высокоуровневые библиотеки.
Deadlock
Deadlock — это ситуация в многозадачной среде, при которой несколько потоков находятся в состоянии ожидания ресурса, занятого друг другом, и ни один из них не может продолжать свое выполнение. Таким образом оба потока бесконечно ожидая друг друга никогда не выполнят задачу, что может привести к неожиданному поведению приложения.
Попробуем воспроизвести самый примитивный кейс бесконечной блокировки ресурса:
Воспроизведем deadlock с использованием вложенных блокировок ресурсов:
Заключение
В заключении хочется сказать, что тема concurrency достаточно большая и сложная, но по мере приближения к высокому уровню, конструкции будут становится проще и понятнее. Скорее всего вам никогда не придется создавать pthread руками, но полезно знать, как работают более высокоуровневые обертки под капотом. В следующих статьях рассмотрим библиотеку GCD, научимся крутить вертеть Operations, прямо как Гудини, а так же копнем еще глубже и изучим все тонкости работы процессора в контексте данной темы. Спасибо за внимание!
Русские Блоги
RunLoop в iOS
RunLoop в iOS
Что такое RunLoop
Буквально это бегущий цикл. Наша общая программа состоит в том, чтобы выполнить поток, который является прямой линией. Есть начальная и конечная точки. Runloop всегда рисует круг на потоке, пробегает круг и постоянно обнаруживает некоторые круги. События щелчков, таймеры и т. Д. Запускают выполнение после обнаружения, снова переводят в спящий режим после выполнения, а затем обнаруживают во время режима сна, если он не отключен, он всегда будет работать, в противном случае он продолжит цикл. Внутренняя структура представляет собой цикл do-while, в котором непрерывно обрабатываются различные задачи (такие как таймер, источник и Observer).
Основная роль RunLoop
RunLoop и потоки
Как видно из приведенного выше кода, существует взаимно-однозначное соответствие между потоками и RunLoop, и отношение сохраняется в глобальном словаре. Когда поток только что был создан, RunLoop не было, если вы не извлекаете его активно, он никогда не будет там. Создание RunLoop происходит при первом получении, а уничтожение RunLoop происходит в конце потока. Вы можете получить его RunLoop только внутри потока (кроме основного потока).
Примечание: инициализация NSRunLoop не требует alloc, нужно только вызвать [NSRunLoop currentRunLoop] в этом потоке,
RunLoop и связанные классы
(В основном для 5 классов RunLoop в Core Foundation)
Класс CFRunLoopModeRef не предоставляется извне, но инкапсулируется через интерфейс CFRunLoopRef. Их отношения таковы:
CFRunLoopModeRef
CFRunLoopModeRef представляет режим запуска RunLoop. Именно потому, что у runloop есть источники, таймеры и наблюдатели, runloop всегда может работать. Без них runloop будет напрямую выходить из цикла.
RunLoop содержит несколько режимов, и каждый режим содержит несколько источников / таймеров / наблюдателей
При каждом запуске RunLoop может быть указан только один из них. Этот режим называется CurrentMode
Если вам нужно переключить режим, вы можете только выйти из цикла и указать новый режим для входа в цикл.
Каждый режим может установить свой собственный источник / таймер / наблюдатель, чтобы он не влиял друг на друга
5 режимов зарегистрированы по умолчанию (Apple открыла только первые два)
kCFRunLoopDefaultMode: режим приложения по умолчанию, обычно основной поток работает в этом режиме.
UITrackingRunLoopMode: режим отслеживания интерфейса, используемый для ScrollerView для отслеживания касания и скольжения, чтобы гарантировать, что другие интерфейсы не будут влиять на интерфейс при скольжении.
UIInitalizaationRunLoopMode: первый режим, введенный при запуске приложения, больше не будет использоваться после запуска
GSEventReceiveRunLoopMode: принимает внутренний режим (отрисовка чертежа и т. Д.) Системных событий, обычно не используемых
kCFRunLoopCommonModes: это режим заполнителя, а не реальный режим
CFRunLoopTimerRef
CFRunLoopSourceRef
CFRunLoopObserverRef
Если вы добавите Observer в runloop, вы можете использовать только функции CF, обычно используемые для перехвата системных событий и т. Д.
Логика обработки RunLoop
Что касается памяти runloop, в runloop runloop будет соответствовать потоку, а пул автоматического выпуска предназначен для некоторых объектов текущего потока, он будет освобожден один раз перед kCFRunLoopBeforeWaiting и в следующий раз Он будет воссоздан при запуске,
Варианты использования RunLoop в разработке
1, запустить резидентный поток (чтобы дочерний поток не входил в мертвое состояние, ожидал сообщений от других потоков, обрабатывал события)
2, может заставить определенные события выполняться в определенном режиме
Если изображение, загруженное из Интернета, отображается в UIScrollView или UITableView, пользовательский интерфейс иногда зависает при скольжении экрана. Вы можете использовать runloop для решения этой проблемы.
Русские Блоги
Подробное объяснение и практика iOS RunLoop
оглавление
-Концепция RunLoop
-RunLoop логика и реализация
-RunLoop используется в iOS
-RunLoop практика
-Концепция RunLoop
В документации Apple RunLoop определяется следующим образом:
Run loops are part of the fundamental infrastructure associated with threads.
A run loop is an event processing loop that you use to schedule work and coordinate the receipt of incoming events. The purpose of a run loop is to keep your thread busy when there is work to do and put your thread to sleep when there is none.
RunLoop Основная функция, связанная с потоками, RunLoop Он используется для планирования работы и координации цикла обработки событий, который принимает входящие события. RunLoop Цель состоит в том, чтобы позволить потоку работать, когда есть задача, и спать, когда нет задачи для обработки.
Работающий цикл получает события из двух разных типов источников. Источник ввода доставляет асинхронные события, обычно сообщения из другого потока или из другого приложения. Событие синхронизации, предоставляемое источником синхронизации, которое происходит в заранее определенное время или интервал повторения. Оба типа источников используют процедуры обработки, зависящие от приложения, когда они прибывают для обработки события.
-RunLoop логика и реализация
CFRunLoopTimerRef Это триггер на основе времени, который можно смешивать с NSTimer, включая длину времени и обратный вызов, добавить
Когда RunLoop, RunLoop зарегистрирует соответствующую точку времени, когда точка времени, RunLoop будет активирован для выполнения этого обратного вызова
CFRunLoopObserverRef Наблюдатель, каждый Observer Оба включают обратный вызов (указатель на функцию). Когда состояние RunLoop изменяется, наблюдатель может получить это изменение через обратный вызов. Моменты времени, которые можно наблюдать, следующие:
-RunLoop используется в iOS
Роль Run Loop
1. Продолжайте работу программы и примите ввод пользователя.
2. Решите, когда программа должна обрабатывать эти события.
3. Разделение вызовов (очередь сообщений)
4. Экономьте процессорное время.
Когда звонить
1. Использовать порт port Или настраиваемый источник ввода input sources Общайтесь с другими темами
2. Используйте таймер потока timer
3. Используйте любой метод performSelector в Какао.
4. Поток выполняет периодические задачи.
Сценарии приложения RunLoop
AutoreleasePool
Вызов стека среды выполнения приложения основного потока
При запуске программы Apple находится в основном потоке RunLoop Добавлены два Observer Для мониторинга RunLoop из kCFRunLoopEntry (Вызвать) и BeforeWating (Готов спать)
GCD
GCD и RunLoop Часть реализации использует друг друга, RunLoop из timer Используется dispatch_source_t Достигнуто, а GCD dispatch_async() Также используется RunLoop
При звонке dispatch_async(dispatch_get_main_queue(), block) Время, dispatch Основной поток RunLoop Послать сообщение, RunLoop Буду разбужен и получу от сообщения block Отправить обратный звонок
Сетевой запрос
основан на CFNetwork из NSURLConnection Инициирован NSURLConnectionLoader В потоке цикл выполнения основан на mach port из Source0 Получите из нижнего слоя CFSocket Обратите внимание, просыпайтесь одновременно delegate с участием RunLoop Для обработки этих уведомлений.
Используется ответ на событие __IOHIDEventSystemClientQueueCallback()
Используется распознавание жестов _UIGestureRecognizerUpdateObserver()
Используется обновление интерфейса _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()
и т. д.
Практика RunLoop
// RunLoop-Поддержание жизненного цикла потока, чтобы поток не выходил автоматически, завершаемся, когда isFinished имеет значение Yes. Перед запуском RunLoop необходимо добавить отслеживаемый порт или источники событий источника ввода или таймер событий источника синхронизации, в противном случае вызов [runloop run] вернется напрямую, не входя в цикл, чтобы позволить потоку остаться. Если событие источника ввода или событие таймера не добавлено, поток всегда будет бездействовать в бесконечном цикле, всегда будет занимать срез времени ЦП, и разумное распределение ресурсов не будет реализовано. Если цикла while нет и к потоку не добавлен источник ввода или таймер, поток завершится напрямую и будет повторно использован системой.
// Новая идея tableView задержки загрузки изображений
// RunLoop-NSTimer работает в разных режимах
// RunLoop-NSTimer создает таймер в потоке
// RunLoop-RunLoop используется в RCTWebSocket в среде ReactNative
// AFURLRequestSerilization RunLoop AFNetWorking
// AFURLConnectionOperationRunLoop использовал резидентные потоки в предыдущих версиях AFNetworking
Релевантная информация:
Официальные документы Справочник по классам NSRunLoop, Справочник по CFRunLoop.
Код CFRunLoopRef:Открытый источникДа вы можете здесьhttp://opensource.apple.com/tarballs/CF/ Загрузите исходный код всего CoreFoundation для просмотра.
Быстрая версия кроссплатформенного CoreFoundation:https://github.com/apple/swift-corelibs-foundation/, Исходный код этой версии может немного отличаться от реализации в существующей системе iOS, но ее легче компилировать, и она адаптирована для Linux / Windows.
Интеллектуальная рекомендация
[Leetcode Tour] Array-697. Степень массива
Добавить расширение Redis для PHP7 под Windows
1 Просмотр информации о версии PHP Непосредственно используйте функцию phpinfo (), вывод в браузер в порядке Результаты вывода, в основном, отображают следующую информацию: версия PHP, архитектура, сб.
неправильная причина: Первичный ключ сущности установлен в режим саморазвития, но первичный ключ идентификатора устанавливается для него при сохранении.
работа на прошлой неделе не особенно подходит для различных причин, рисунок слайдера имеет узкое и не будет завершена на этой неделе, но это хорошо, чтобы быть в разработке и продвижении персонажа и д.
Том Зибель технические книги рекомендуется
iOS разработка программного обеспечения 1. Опытный в Objective-C [США] Кит Ли, Су Баолонг Народная почта и телекоммуникационная пресса Эта книга подходит для некоторых разработчиков, которые уже начал.