2016-10-21 1 views
1

I가 완료 콜백 USB 장치로부터의 데이터를 커맨드를 송신하고 무한 루프 판독 기능 가지고출구 너무 오랫동안 동작을 수행하는 경우

func dump(success: (() -> Void)? = nil, failure: (()->Void)? = nil) { 
    HIDDevice.sharedInstance.sendCommad(command: "dump") 
    while true { 
     for data in HIDDevice.sharedInstance.readBuf { 
      if data == "dumpcomplete": 
       success?() 
       return 
     } 
    } 
} 

하고 난이 잠시 있는지 확인해야 루프가 > 1 초를 초과하여 성공하지 못하면 failure 클로저 및 중지 루프를 호출하십시오.

이전에 루프를 사용하려고했지만 도움이되지 않았습니다. 루프를 기준으로 스레드를 스레드하십시오.

func setTimeout(delay:TimeInterval, block:@escaping()->Void) -> Timer { 
    return Timer.scheduledTimer(timeInterval: delay, target: BlockOperation(block: block), selector: #selector(Operation.main), userInfo: nil, repeats: false) 
} 

let handle = setTimeout(1, block: {() -> Void in 
    failure()? 
    return 
}) 
+1

바쁜 루프가 나쁘다. 'readBuf'는 데이터가 없으면 차단하거나 단순히 리턴합니까? – rmaddy

+0

@rmaddy이 클래스는 https://github.com/bettse/KuandoSwift/blob/master/KuandoSwift/BusyLight.swift#L20 이며 'ViewController'에서 데이터를 읽는 유일한 방법은 임시 변수 – Arti

+0

에서 읽는 것입니다. (r, g, b) : (UInt8, UInt8, UInt8) = (0, 0xff, 0) 한 줄로'r','g' 및'b'의 할당을 압축 할 수 있습니다.)' – Alexander

답변

3

I는 "바쁜 루프"를 생각하지 않지만 내가 그래서 이러한 루프에 대한 대안을 제공 할 수 HIDDevice에 대해 아무것도 몰라, 좋은 생각이다. 따라서이 답변은 1 초 후에 while 루프를 종료하는 방법에 대한 직접적인 질문만을 다룹니다.

func dump(success: (() -> Void)? = nil, failure: (()->Void)? = nil) { 
    HIDDevice.sharedInstance.sendCommad(command: "dump") 
    let deadline = Date.timeIntervalSinceReferenceDate + 1 // add one second from now 
    while Date.timeIntervalSinceReferenceDate < deadline { 
     for data in HIDDevice.sharedInstance.readBuf { 
      if data == "dumpcomplete": 
       success?() 
       return 
     } 
    } 
} 

이것은 미래의 시간 간격을 계산하고, 미래의 값에 대해 현재 시간을 확인 :

한 가지 해결책은 시간 간격을 계산할 때마다 확인하는 것이다. 그 시간이 지나면 while 루프가 종료됩니다. 그랜드 센트럴 디스패치를 ​​사용

+0

나는 더 나은 해결책이 있다고 생각한다 : GCD를 타임 아웃과 함께 사용하라. 이전에 GCD를 사용하지 않았으므로 대답하기 전에 놀기에는 초를 보냅니다. – Alexander

+0

@AlexanderMomchliov, GCD를 기다려 주셔서 감사합니다. 예,'''while 루프''는 끔찍한 것처럼 보이지만 장치에서 데이터를 올바르게 읽는 유일한 방법 일뿐입니다. – Arti

+0

@AlexanderMomchliov 내가이 클래스가 : 데이터를 읽을 수 https://github.com/bettse/KuandoSwift/blob/master/KuandoSwift/BusyLight.swift#L20 및 유일한 방법은'ViewController'는 – Arti

2

rmaddyy의 대답은 작동하지만, 현재 시간의 지속적인 샘플링은 정말 비싼 가져옵니다.

다른 방법으로는 다중 스레드를 제안합니다. 다음은 루핑을 수행하고 제한 시간 후에 루핑을 중지하는 함수입니다. 또한 루프가 성공적으로 끝났거나 시간이 초과되었는지 알려주는 DispatchTimeoutResult을 반환합니다.

import Dispatch 

func BusyLoop(timeout: DispatchTimeInterval, 
       qos: DispatchQoS = .background, 
       _ block: @escaping @convention(block) (() -> Void) -> Void) -> DispatchTimeoutResult { 
    var shouldLoop = true; 
    let BreakLoop = { shouldLoop = false } //callback to stop looping 

    let item = DispatchWorkItem() { 
     while shouldLoop { 
      block(BreakLoop) 
     } 
    } 

    let queue = DispatchQueue(label: "Busy Loop", qos: qos) //TODO: Name me 
    queue.async(execute: item) 

    let state = item.wait(timeout: .now() + timeout) 
    if state == .timedOut { 
     shouldLoop = false 
    } 

    return state 
} 

var i = 0 

BusyLoop(timeout: .seconds(1)) { BreakLoop in 
    //treat this as the loop body 
    print(i) 
    i += 1 

    if i == 1000 { BreakLoop() } //treat this as "break" 
    // "return" acts as "continue" 
} 


switch timeoutResult { 
case .success: print("Finished on time") 
case .timedOut: print("Timed out") 
} 

여기에 당신의 사건에 대한 샘플 구현의 :

func dump(success: (() -> Void)? = nil, failure: (()->Void)? = nil) { 
    HIDDevice.sharedInstance.sendCommad(command: "dump") 

    let timeoutResult = BusyLoop(timeout: .seconds(1)) { BreakLoop in 
     for data in HIDDevice.sharedInstance.readBuf { 
      switch data { 
       case "dumpcomplete": 
        success?() 
        BreakLoop() 
       default: BreakLoop() //handle other cases 
      } 
     } 
    } 

    switch timeoutResult { 
    case .success: 
     print("Finished on time") 
     success?() 
    case .timedOut: 
     print("Timed out") 
     failure?() 
    } 
} 
+2

임시 변수에서 읽는 것입니다 이 경우 WorkItem이 누수됩니다. 프로세서 등을 사용하여 실행을 계속할 것이며 기다리지 않고 결과를 얻을 수 없습니다. 어떻게 든 rmaddy가 취소 한 것처럼 취소되지 않았다면, 그 문제를 피할 수는 없습니다. 블록 외부에서 블록을 중단 할 방법이 없습니다 (Swift에서 안전하게 수행 할 수있는 방법은 없습니다). –

+0

@RobNapier 오, 그래, 나는 그것을 고려하지 않았다. 흠, 고쳐 줄 방법이있어? – Alexander

+1

rmaddy 님의 답변입니다. 아무리 당신이 그것을 지었다하더라도, 결국 당신은 "우리가 멈춰야합니까?"while 루프의 조건부에서 (분명히 원한다면 좀 더 일반화 할 수있는 방법이 있지만, 이런 종류의 루핑은 일반적으로 많은 시간을 쓰지 않고 일반적인 Swift 패턴이 아닙니다.) –

관련 문제