ПРИМЕЧАНИЕ: См исправленный пост ниже: Re: Оборудование зеркалированиеSwift «Array» распределение памяти, плюс переключатель зеркального отображения
Я написал две Swift функции, переключать отображение зеркального отображения в OSX. Обе работы; разница между ними - это просто синтаксис при работе с указателями. Для удобства тех, кто заинтересован в том, как переключать зеркалирование в Swift, я включил текст файла детской площадки ниже.
Вопрос о распределении памяти. Здесь секция интереса:
toggleMirroringUgly
// allocate space for array
let displayListPtr = displayIDListPtr.alloc(Int(displayCount)) //see typealias above
// fill the list
postError(CGGetActiveDisplayList(displayCount, displayListPtr, &activeCount))
toggleMirroring
// allocate space for list of displays
var displayIDList = Array<CGDirectDisplayID>(count: Int(displayCount), repeatedValue: kCGNullDirectDisplay)
// fill the list
postError(CGGetActiveDisplayList(displayCount, &displayIDList, &activeCount))
CGGetActiveDisplayList является вызов функции низкого уровня, которая опирается на данные расположены в последовательных ячейках памяти. Я достаточно уверен, что «alloc» из уродливой версии смежна. Эмпирически кажется, что вызов «Array (...)» также смежный, но могу ли я полагаться на то, что всегда истинно (например, если число дисплеев растет)? Это предположение о неправильной форме инициализатора массива Swift?
Вот и все код; извинения за проблемы форматирования. Обратите внимание, что нужно вызывать только одну из двух функций; в противном случае вы закончите с того, с чего вы начали.
//: Playground - noun: a place where people can play
import Cocoa
// apparently not defined in Swift version of SDK 10.11 (XCode 7.3.1), so add manually
let kCGNullDirectDisplay = CGDirectDisplayID(0)
let kCGDirectMainDisplay = CGMainDisplayID() // not used here, just for the record
let maxDisplays:UInt32 = 20 // not used
var onlineCount:UInt32 = 0 // not used
func postError(error : CGError){
if error != CGError.Success {
print("got an error")
}
}
// this toggles all active displays, online or not
func toggleMirroring(){
var displayCount:UInt32 = 0
var activeCount:UInt32 = 0
//var onlineCount:UInt32 = 0 //not used
//get count of active displays (by passing nil to CGGetActiveDisplayList
postError(CGGetActiveDisplayList(0, nil, &displayCount))
if displayCount < 2 { return } // no point in any mirroring functions
//***
// allocate space for list of displays
var displayIDList = Array<CGDirectDisplayID>(count: Int(displayCount), repeatedValue: kCGNullDirectDisplay)
// fill the list
postError(CGGetActiveDisplayList(displayCount, &displayIDList, &activeCount))
//***
// determine if mirroring is active
// hack to convert from boolean_t (aka UInt32) to swift's bool
let displaysMirrored = CGDisplayIsInMirrorSet(CGMainDisplayID()) != 0
// set master based on current mirroring state
// if mirroring, master = null, if not, master = main display
let master = (true == displaysMirrored) ? kCGNullDirectDisplay : CGMainDisplayID()
// start the configuration
var configRef:CGDisplayConfigRef = nil //swift 3 syntax
postError(CGBeginDisplayConfiguration(&configRef));
for i in 0..<Int(displayCount) {
let currentDisplay = CGDirectDisplayID(displayIDList[i])
if CGMainDisplayID() != currentDisplay {
CGConfigureDisplayMirrorOfDisplay(configRef, currentDisplay, master);
}
}
if (false){ // change to true in order to execute the toggle
postError(CGCompleteDisplayConfiguration (configRef,CGConfigureOption.Permanently))
}
// The first entry in the list of active displays is the main display. In case of mirroring, the first entry is the largest drawable display or, if all are the same size, the display with the greatest pixel depth.
// The "Permanently" option might not survive reboot when run from playground, but does when run in an application
}
func toggleMirroringUgly(){
// just to decrease eye strain
typealias displayIDListPtr = UnsafeMutablePointer<CGDirectDisplayID>
typealias configurationRefPtr = UnsafeMutablePointer<CGDisplayConfigRef>
//get count of active displays (by passing nil to CGGetActiveDisplayList
postError(CGGetActiveDisplayList(0, nil, &displayCount))
if displayCount < 2 { return } // no point in any mirroring functions
// ***
// allocate space for array
let displayListPtr = displayIDListPtr.alloc(Int(displayCount)) //see typealias above
// fill the list
postError(CGGetActiveDisplayList(displayCount, displayListPtr, &activeCount))
// ***
// determine if mirroring is active
// hack to convert from boolean_t (aka UInt32) to swift's bool
let displaysMirrored = CGDisplayIsInMirrorSet(CGMainDisplayID()) != 0
// set master based on current mirroring state
// if mirroring master = null, if not, master = main display
let master = (true == displaysMirrored) ? kCGNullDirectDisplay : CGMainDisplayID()
// make room for the configuration reference
let configRefPtr = configurationRefPtr.alloc(1) //see typealias above
// start the configuration
postError(CGBeginDisplayConfiguration (configRefPtr));
for i in 0..<displayCount {
let currentDisplay = CGDirectDisplayID(displayListPtr[Int(i)])
if CGMainDisplayID() != currentDisplay {
CGConfigureDisplayMirrorOfDisplay(configRefPtr[0], currentDisplay, master);
}
}
if (false){ //change to true in order to flip the mirroring
// make it happen
postError(CGCompleteDisplayConfiguration (configRefPtr[0],CGConfigureOption.Permanently));
}
// The first entry in the list of active displays is the main display. In case of mirroring, the first entry is the largest drawable display or, if all are the same size, the display with the greatest pixel depth.
// The "Permanently" option might not survive reboot when run from playground, but does when run in an application
}
toggleMirroring()
Большое спасибо за понимание!Я ценю, как вы 1) ответили на вопрос, с полезной ссылкой на тип «ContiguousArray» и 2) обобщили решение, которое я признаю, что не понимаю полностью. Для CGGetActiveDisplayList меня не так беспокоит, что количество активных дисплеев изменится в nsec между первым вызовом и вторым, но CGGetActiveDisplayList будет записывать в неправильно распределенную память. Действительно, код не использует activeCount, возвращенный вторым вызовом. – MDF
Действительно, для этого может быть нередко меняться между вызовами, но если мое чтение API верное, возможно, это возможно. Конкретное обобщение, которое я предлагаю, может оказаться неправильным для вас, но я считаю, что обычно полезно обертывать громоздкие API с помощью какой-либо вспомогательной функции или расширения. Возможно, вы могли бы попробовать создать одну функцию, задача которой - вернуть список идентификаторов отображения. (Вы также можете обсудить настройки API в списке рассылки быстрой эволюции - наложения API - это [open-source] (https://github.com/apple/swift/blob/master/stdlib/public/SDK/CoreGraphics/CoreGraphics .swift).) – jtbandes