2016-12-05 8 views
1

누구나 Swift에서 Core Foundation의 CFBinaryHeap 데이터 구조에 CFBinaryHeapGetValues를 호출하는 방법에 대해 설명해 줄 수 있습니까? 코드 샘플/예제는 많은 도움이 될 것입니다. 당신이 코드는 내가 EXC_BAD_ACCESS를 얻을 마지막 줄에 실패 마지막 세 줄에 위에서 보면CFBinaryHeapGetValues ​​()를 올바르게 호출하고 Swift에서 결과 C 배열을 구문 분석하는 방법은 무엇입니까?

public class CountedColor : NSObject 
{ 
    public private(set) var count: Int 
    public private(set) var color: UIColor 

    public init(color: UIColor, colorCount: Int) 
    { 
     self.count = colorCount 
     self.color = color 
     super.init() 
    } 
} 

var callbacks = CFBinaryHeapCallBacks() 

callbacks.compare = { (a,b,unused) in 
    let afoo : CountedColor = (a?.assumingMemoryBound(to: CountedColor.self).pointee)! 
    let bfoo : CountedColor = (b?.assumingMemoryBound(to: CountedColor.self).pointee)! 

    if (afoo.count == bfoo.count) { return CFComparisonResult.compareEqualTo } 
    if (afoo.count > bfoo.count) { return CFComparisonResult.compareGreaterThan } 
    return CFComparisonResult.compareLessThan 
} 

let callbackPointer = UnsafeMutablePointer<CFBinaryHeapCallBacks>.allocate(capacity: 1) 
callbackPointer.initialize(to: callbacks) 
var bh = CFBinaryHeapCreate(nil, 0, callbackPointer, nil) 

var fooPointer : UnsafeMutablePointer<CountedColor>! 
fooPointer = UnsafeMutablePointer<CountedColor>.allocate(capacity: 1) 
fooPointer.initialize(to: CountedColor(color: UIColor.blue, colorCount: 72)) 
CFBinaryHeapAddValue(bh, fooPointer) 
fooPointer = UnsafeMutablePointer<CountedColor>.allocate(capacity: 1) 
fooPointer.initialize(to: CountedColor(color: UIColor.red, colorCount: 99)) 
CFBinaryHeapAddValue(bh, fooPointer) 

var elements = [CountedColor](repeating: CountedColor(color: UIColor.white, colorCount: 0), count: 2) 
var elementPtr = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 1) 
elementPtr.initialize(to: elements) 
CFBinaryHeapGetValues(bh, elementPtr) 

var returnedValues: UnsafePointer<[CountedColor]> = (elementPtr.pointee?.assumingMemoryBound(to: [CountedColor].self))! 
print(elementPtr.pointee?.assumingMemoryBound(to: CountedColor.self).pointee.count) 
print(elementPtr.pointee?.assumingMemoryBound(to: CountedColor.self).pointee.color) 
let values = returnedValues.pointee 

^^ : 이것은 내가 현재 가지고있는 코드입니다. 위의 두 인쇄 문이 실제로 작동하기 때문에 나는 왜 혼란스러워합니다. 함수에 의해 반환 된 C 배열의 첫 번째 개체가 참으로 카운트가 72 인 작은 색상인지 확인할 수 있습니다. 따라서 전달할 배열은 값으로 업데이트되지만 핸들을 얻으려고하면 pointee에 액세스하여 배열에 건초는 간다. 처음에는 이것이 메모리 관리 일이라고 생각했지만, Swift에서 브리징이 어떻게 작동 하는지를 읽은 후에, 특히 이것이 Annotated CoreFoundation API이므로 이것이 확실하지 않은지 잘 모르겠습니다. 코드에서

답변

1

:

CFBinaryHeapAddValue(bh, fooPointer) 

당신은 UnsafeMutablePointer<CountedColor>, 두 번 통과하고 있습니다.

은 (요소의 수는 많은 부분에 영향을 미친다.) CFBinaryHeapGetValues(bh, elementPtr)를 호출 할 때

그래서, 당신은 두 UnsafeMutablePointer<CountedColor>의를 포함 할 수 있습니다 C 배열에 대한 영역을 확보 할 필요가있다.

var elementPtr = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 2) //<- You need to allocate a region for two elements 
elementPtr.initialize(to: nil, count: 2) //<- The content is overwritten, initial values can be nil 
CFBinaryHeapGetValues(bh, elementPtr) 

그리고이 코드 :

당신은 같이 작성해야

var returnedValues: UnsafePointer<[CountedColor]> = (elementPtr.pointee?.assumingMemoryBound(to: [CountedColor].self))! 

나는 UnsafeMutablePointer<CountedColor>의 아닌 UnsafePointer<[CountedColor]> 있으며, 위 elementPtr가 가리키는 영역에 저장된 결과를 썼던 것처럼.

elementPtr.pointee 첫 번째 UnsafeMutablePointer<CountedColor> 검색, 그래서 당신이 print 문은 작동하지만 그 코드의 returnedValues가 예상 뭔가를 들고 의미하지 않는다.

C- 배열을 처리하는 좋은 방법 중 하나는 UnsafeBufferPointer입니다.

let returnedValues = UnsafeBufferPointer(start: elementPtr, count: 2) 

UnsafeBufferPointer 컬렉션 형식으로 작품을, 그래서 당신은 쉽게 Array로 변환 할 수 있습니다.

let values = returnedValues.map{$0!.load(as: CountedColor.self)} 

는 그리고 deinitializedeallocateallocate 에드 지역에 잊지 마십시오.

이렇게하려면 할당 된 모든 포인터와 개수를 유지해야합니다. 그래서, 당신은 같은 코드의 일부를 변경해야 할 수도 있습니다 : 그런 후 당신의 CFBinaryHeap (bh)를 사용하여 완료

var fooPointer : UnsafeMutablePointer<CountedColor>! 
fooPointer = UnsafeMutablePointer<CountedColor>.allocate(capacity: 1) 
fooPointer.initialize(to: CountedColor(color: UIColor.blue, colorCount: 72)) 
CFBinaryHeapAddValue(bh, fooPointer) 
var barPointer : UnsafeMutablePointer<CountedColor>! 
barPointer = UnsafeMutablePointer<CountedColor>.allocate(capacity: 1) 
barPointer.initialize(to: CountedColor(color: UIColor.red, colorCount: 99)) 
CFBinaryHeapAddValue(bh, barPointer) 

...

elementPtr.deinitialize(count: 2) 
elementPtr.deallocate(capacity: 2) 
barPointer.deinitialize() 
barPointer.deallocate(capacity: 1) 
fooPointer.deinitialize() 
fooPointer.deallocate(capacity: 1) 

당신은, 당신은 같은 것을 쓸 수 경우, CFBinaryHeap에 CountedColor의 임의의 수를 추가 할 수 있습니다

:

let colors = [ 
    CountedColor(color: UIColor.blue, colorCount: 72), 
    CountedColor(color: UIColor.red, colorCount: 99), 
    //... 
] 
var fooPointer : UnsafeMutablePointer<CountedColor>! 
fooPointer = UnsafeMutablePointer<CountedColor>.allocate(capacity: colors.count) 
fooPointer.initialize(from: colors) 
for i in colors.indices { 
    CFBinaryHeapAddValue(bh, fooPointer+i) 
} 

이 (당신은 모든 count:을 변경해야 할 수도 있습니다를 s 또는 capacity:의 코드는 colors.count입니다.

그리고

elementPtr.deinitialize(count: colors.count) 
elementPtr.deallocate(capacity: colors.count) 
fooPointer.deinitialize(count: colors.count) 
fooPointer.deallocate(capacity: colors.count) 

어쨌든, 경기 initializedeinitialize, allocatedeallocate. 내가 upvoted과 답변을 수락 한

+0

당신은 코드를 개선하기 위해 스위프트 표준 라이브러리에서 몇 가지 유용한 유형을 찾을 수 있지만, 한 번에 너무 많은 일을 배울 수있는 좋은 습관이 될 수 없습니다 ..., 감사합니다 너무 많이! 나는이 점을 훨씬 잘 이해한다. 빠른 후속 질문입니다. 당신이 작성한 코드의 마지막 줄에서, 그 함수는 어떻게 작동합니까? 내가 아는 바로는 무효 포인터이다. 그런 다음 Swift는 어떻게 원시 바이트를 읽고 CountedColor 객체를 만드는지를 알 수 있습니다. 설명서를 읽었지만 여전히 도움이되지 않았습니다. 이것은 솔직히 objC, C++ 및 C 세계에서 나오는 마법과 같아 보입니다. C와의 신속한 상호 운용은 일반적으로 나에게 마술처럼 보입니다. ( – AyBayBay

+0

@AyBayBay, _how는 함수 작업으로로드를 수행합니까? _'(* SomeType *) aVoidPointer '와 같이 C에서 일부 내용을 검색 할 때'void *'를 적절한 유형으로 캐스팅합니다. Swift에서 'aVoidPointer.load (as : SomeType.self)'는 이에 상응합니다 아니면'aVoidPointer.assumingMemoryBound (to : SomeType.self) .pointee'의 바로 가기 형태라고 생각할 수 있습니다. – OOPer

+0

대단히 감사합니다. :) 마지막으로 질문을 하나 더 드리겠습니다. 필요한 객체를 검토하고 싶습니다. 할당 취소/무료. 내가 callbackPtr, 모든 UnsafeMutablePointer 개체를 내가 BinaryHeap에 추가하고 마지막으로 elementPtr과 그 안에있는 개체를 상상할 것이라고 생각합니다. 여기 내 이해가 맞습니까? – AyBayBay