С Swift 3, Grand Central Dispatch предлагает множество способов решить вашу проблему. В соответствии с вашими потребностями вы можете выбрать один из шести шаблонов, показанных в следующих фрагментах игровой площадки.
DispatchGroup
, DispatchGroup
notify(qos:flags:queue:execute:)
и DispatchQueue
async(group:qos:flags:execute:)
Руководство по программированию параллельного программирования Apple Developer указывает на DispatchGroup
:
Группы отправки - это способ блокировать поток, пока не завершится выполнение одной или нескольких задач. Вы можете использовать это поведение в тех местах, где вы не можете добиться прогресса, пока все указанные задачи не будут завершены. Например, после отправки нескольких задач для вычисления некоторых данных вы можете использовать группу для ожидания этих задач, а затем обрабатывать результаты, когда они будут выполнены.
blockquote>import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent) let group = DispatchGroup() queue.async(group: group) { print("#1 started") Thread.sleep(forTimeInterval: 5) print("#1 finished") } queue.async(group: group) { print("#2 started") Thread.sleep(forTimeInterval: 2) print("#2 finished") } group.notify(queue: queue) { print("#3 finished") } /* prints: #1 started #2 started #2 finished #1 finished #3 finished */
# 2. Используя
DispatchGroup
,DispatchGroup
wait()
,DispatchGroup
enter()
иDispatchGroup
leave()
import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent) let group = DispatchGroup() group.enter() queue.async { print("#1 started") Thread.sleep(forTimeInterval: 5) print("#1 finished") group.leave() } group.enter() queue.async { print("#2 started") Thread.sleep(forTimeInterval: 2) print("#2 finished") group.leave() } queue.async { group.wait() print("#3 finished") } /* prints: #1 started #2 started #2 finished #1 finished #3 finished */
Обратите внимание, что вы также можете смешать
DispatchGroup
wait()
сDispatchQueue
async(group:qos:flags:execute:)
или миксDispatchGroup
enter()
иDispatchGroup
leave()
сDispatchGroup
notify(qos:flags:queue:execute:)
.# 3. Использование свойства
DispatchWorkItemFlags
barrier
иDispatchQueue
DispatchQueue
async(group:qos:flags:execute:)
Учебное пособие по центральному диспетчерскому центру для Swift 3: Part 1/2 статья Raywenderlich.com дает определение барьеров :
Барьеры отправки - это группа функций, выполняющих узкие места в последовательном стиле при работе с параллельными очередями. [...] Когда вы отправляете
blockquote>DispatchWorkItem
в очередь отправки, вы можете установить флаги, чтобы указать, что он должен быть единственным элементом, выполняемым в указанной очереди за это конкретное время. Это означает, что все элементы, отправленные в очередь до барьера отправки, должны завершиться до выполненияDispatchWorkItem
.Использование:
import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent) queue.async { print("#1 started") Thread.sleep(forTimeInterval: 5) print("#1 finished") } queue.async { print("#2 started") Thread.sleep(forTimeInterval: 2) print("#2 finished") } queue.async(flags: .barrier) { print("#3 finished") } /* prints: #1 started #2 started #2 finished #1 finished #3 finished */
# 4. Используя
DispatchWorkItem
, свойствоDispatchWorkItemFlags
barrier
иDispatchQueue
async(execute:)
import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent) queue.async { print("#1 started") Thread.sleep(forTimeInterval: 5) print("#1 finished") } queue.async { print("#2 started") Thread.sleep(forTimeInterval: 2) print("#2 finished") } let dispatchWorkItem = DispatchWorkItem(qos: .default, flags: .barrier) { print("#3 finished") } queue.async(execute: dispatchWorkItem) /* prints: #1 started #2 started #2 finished #1 finished #3 finished */
# 5. Используя
DispatchSemaphore
,DispatchSemaphore
wait()
иDispatchSemaphore
signal()
методыСоруш Ханлоу написал следующие строки в Сообщение в блоге GCD Handbook :
Используя семафор, мы можем заблокировать поток в течение произвольного промежутка времени, пока сигнал из другого потока не будет послал. Семафоры, как и остальные GCD, являются потокобезопасными, и их можно запускать из любого места. Семафоры могут использоваться, когда есть асинхронный API, который вам нужно сделать синхронным, но вы не можете его изменить.
blockquote>Справочник API разработчика Apple также дает следующее обсуждение для
DispatchSemaphore
init(value:)
initializer:Передача нуля для значения полезна, когда двум потокам необходимо согласовать завершение определенного события. Передача значения больше нуля полезно для управления конечным пулом ресурсов, где размер пула равен значению.
blockquote>Использование:
import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent) let semaphore = DispatchSemaphore(value: 0) queue.async { print("#1 started") Thread.sleep(forTimeInterval: 5) print("#1 finished") semaphore.signal() } queue.async { print("#2 started") Thread.sleep(forTimeInterval: 2) print("#2 finished") semaphore.signal() } queue.async { semaphore.wait() semaphore.wait() print("#3 finished") } /* prints: #1 started #2 started #2 finished #1 finished #3 finished */
# 6. Используя
OperationQueue
иBlockOperation
Справочник API разработчика Apple содержит информацию о
OperationQueue
:Операционные очереди используют библиотеку
blockquote>libdispatch
(также известную как Grand Central Dispatch), чтобы инициировать выполнение своих операций.Использование:
import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true let operationQueue = OperationQueue() let blockOne = BlockOperation { print("#1 started") Thread.sleep(forTimeInterval: 5) print("#1 finished") } let blockTwo = BlockOperation { print("#2 started") Thread.sleep(forTimeInterval: 2) print("#2 finished") } let blockThree = BlockOperation { print("#3 finished") } blockThree.addDependency(blockOne) blockThree.addDependency(blockTwo) operationQueue.addOperations([blockThree, blockTwo, blockOne], waitUntilFinished: false) /* prints: #1 started #2 started #2 finished #1 finished #3 finished or #2 started #1 started #2 finished #1 finished #3 finished */
Невозможно получить давление из SDK или недокументированных методов. Однако вы можете определить размер прикосновения с недокументированными методами.
В GSEvent, который является нижнеуровневым представлением UIEvent, существует структура, известная как GSPathInfo с членами:
typedef struct GSPathInfo {
unsigned char pathIndex; // 0x0 = 0x5C
unsigned char pathIdentity; // 0x1 = 0x5D
unsigned char pathProximity; // 0x2 = 0x5E
CGFloat pathPressure; // 0x4 = 0x60
CGFloat pathMajorRadius; // 0x8 = 0x64
CGPoint pathLocation; // 0xC = 0x68
GSWindowRef pathWindow; // 0x14 = 0x70
} GSPathInfo;
Мы замечаем, что существует pathPressure
и pathMajorRadius
. Уверяю вас, что член давления бесполезен - он всегда дает 0. Однако pathMajorRadius
действительно содержит значимую информацию - он дает основной радиус касания в миллиметрах. Поэтому вы можете дать крайне грубую оценку, если это тяжелое прикосновение или легкое прикосновение из радиуса.
-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
GSEventRef gsevent = [event _gsEvent];
GSPathInfo first_touch = GSEventGetPathInfoAtIndex(gsevent, 0);
if (first_touch.pathMajorRadius >= 9)
NSLog(@"huge (heavy) touch");
else
NSLog(@"little (light) touch");
}
Позвольте еще раз предупредить, что это недокументировано , и вы не должны использовать его в приложениях AppStore.
Edit: На 3.2 и выше pathMajorRadius
GSPathInfo также доступен как недокументированное свойство в UITouch:
@property(assign, nonatomic, setter=_setPathMajorRadius:) CGFloat _pathMajorRadius;
так что вышеприведенный код можно переписать, используя чистый Objective-C:
-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
UITouch* any_touch = [touches anyObject];
if (any_touch._pathMajorRadius >= 9)
NSLog(@"huge (heavy) touch");
else
NSLog(@"little (light) touch");
}
Это невозможно с SDK. Он в любом случае не подвергает этих данных. И экран не ощущает давление, а в нем даже отчеты о сенсорных «размерах» к ОС неизвестен. Так к сожалению, то, что вы пытаетесь сделать, это невозможно на законе о приложении.
Я знаю, потому что я спросил то же самое: Может ли iPhone определить размер прикосновения?
В iOS 3.2 и 4.0 вы можете получить значение более прямо, например, так:
UITouch* touch = ...// get the touch object
float radius = [[touch valueForKey:@"pathMajorRadius"] floatValue];
Все еще не одобрено App Store, но удобно для пользовательских вещей.