Можно ли вообще сказать, как сильно нажимается экран?

С Swift 3, Grand Central Dispatch предлагает множество способов решить вашу проблему. В соответствии с вашими потребностями вы можете выбрать один из шести шаблонов, показанных в следующих фрагментах игровой площадки.


# 1. Используя методы 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. Использование свойства Dispatch​Work​Item​Flags barrier и DispatchQueue DispatchQueue async(group:qos:flags:execute:)

Учебное пособие по центральному диспетчерскому центру для Swift 3: Part 1/2 статья Raywenderlich.com дает определение барьеров :

Барьеры отправки - это группа функций, выполняющих узкие места в последовательном стиле при работе с параллельными очередями. [...] Когда вы отправляете DispatchWorkItem в очередь отправки, вы можете установить флаги, чтобы указать, что он должен быть единственным элементом, выполняемым в указанной очереди за это конкретное время. Это означает, что все элементы, отправленные в очередь до барьера отправки, должны завершиться до выполнения DispatchWorkItem.

blockquote>

Использование:

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 , свойство Dispatch​Work​Item​Flags 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 содержит информацию о Operation​Queue:

Операционные очереди используют библиотеку libdispatch (также известную как Grand Central Dispatch), чтобы инициировать выполнение своих операций.

blockquote>

Использование:

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
 */

13
задан Jab 20 January 2010 в 17:26
поделиться

3 ответа

Невозможно получить давление из 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");
  }
28
ответ дан 1 December 2019 в 17:31
поделиться

Это невозможно с SDK. Он в любом случае не подвергает этих данных. И экран не ощущает давление, а в нем даже отчеты о сенсорных «размерах» к ОС неизвестен. Так к сожалению, то, что вы пытаетесь сделать, это невозможно на законе о приложении.

Я знаю, потому что я спросил то же самое: Может ли iPhone определить размер прикосновения?

1
ответ дан 1 December 2019 в 17:31
поделиться

В iOS 3.2 и 4.0 вы можете получить значение более прямо, например, так:

UITouch* touch = ...// get the touch object
float radius = [[touch valueForKey:@"pathMajorRadius"] floatValue];

Все еще не одобрено App Store, но удобно для пользовательских вещей.

12
ответ дан 1 December 2019 в 17:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: