2016-03-21 2 views
1

Я использовал этот блок кода, чтобы найти окно ID У одного активного приложения в течение нескольких месяцев:CFArray takeRetainedValue() удаление вызывает сбой

let info = CGWindowListCopyWindowInfo(CGWindowListOption(kCGWindowListOptionAll), CGWindowID(0)).takeRetainedValue() 
      for dict in info as! [ [ String : AnyObject ] ] { 
       if let windowName = dict["kCGWindowName"] as? String{ 
        if(windowName == "MyWindowName"){ 
         let windowID = dict["kCGWindowNumber"] as! Int 
         println("found window, window number: \(windowID)") 
         return 
        } 
       } 
      } 

На недавнем Swift обновления, однако, takeRetainedValue() и его коллега takeUnretainedValue(), похоже, были удалены. Каждое сообщение об этом в Интернете, которое я могу найти, говорит, что просто удаление вызова должно заставить его работать с более или менее одинаковым поведением, но когда я это делаю, приложение всегда вылетает с прекрасным «Thread 1: EXC_BAD_INSTRUCTION» (code = EXC_i386_INVOP, subcode = 0x0) "в строке" for dict in info ", прежде чем цикл может даже начаться.

Я потратил часы и часы, пытаясь решить проблему, и я нашел кучу отведений, но ни один из них не взял меня нигде. Я понял, что это связано с удалением takeRetainedValue(), оставляя меня с неуправляемым объектом CFArray, но я все еще учусь и не знаю, куда идти отсюда.

Есть ли способ исправить проблему, с которой я сталкиваюсь, или если нет, другой подход, который я должен использовать полностью?

ответ

3

Есть некоторые фанковые изменения для доступа к объектам CoreFoundation в Swift 2. Вам больше не нужно брать сохраненное или неиспользованное значение из CFArray, вы можете связать его напрямую с массивом Swift. Вы получаете крах, потому что вы пытаетесь нарисовать CFArray до [[String : AnyObject]] во время выполнения, и он возвращает nil.

CGWindowListCopyWindowInfoCFArray? (необязательно CFArray). Пытаться к мосту CFArray? - [AnyObject] не удастся, но переключение на дополнительный массив Swift ([AnyObject]?) будет работать. Но для того, чтобы проходить через этот массив, мы должны развернуть его. Здесь я проверяю, если CFArray возвращаемый CGWindowListCopyWindowInfo может быть развернута и мостиком [AnyObject]!:

if let info = CGWindowListCopyWindowInfo(.OptionAll, CGWindowID(0)) as [AnyObject]! { 
    for dict in info { 
     if let windowName = dict[kCGWindowName as String] as? String { 
      if (windowName == "MyWindowName"){ 
       let windowID = dict[kCGWindowNumber as String] as? Int 
       print("found window, window number: \(windowID)") 
       break 
      } 
     } 
    } 
} 

Если по какой-либо причине CGWindowListCopyWindowInfo возвращает NIL, мы не будем пытаться итерацию через него.

отметить также, что CFString константы kCGWindowName и kCGWindowNumber может быть устранен в Swift String объект не проблема. Лучше использовать константы, чем жестко закодированные строки, так как значение константы может меняться со временем.

+0

Большое спасибо за объяснение и отличные предложения! Теперь все становится намного лучше. Как отличать эти 'CFString' с Swift 'String 'предотвращают будущие изменения от возникновения проблем? Какое значение имеет тип объекта String, если это значение может быть изменено? –

+0

@ JackB.Cousineau В исходном коде, который вы передаете, есть '' kCGWindowName "', который является строковым литералом. Что (я считаю), вы действительно хотите, это константа ['kCGWindowName'] (https://developer.apple.com/library/mac/documentation/Carbon/Reference/CGWindow_Reference/#//apple_ref/doc/constant_group/Optional_Window_List_Keys) , что указывает на некоторое значение CFString в SDK. Apple предоставляет константы для этих значений в случае, если базовое строковое представление изменяется в зависимости от версии SDK. – JAL

+0

Ах, я понимаю. Спасибо за вашу помощь! –