2014-11-27 24 views
6

Tôi mới đến nhanh và tôi gặp một số khó khăn trong việc xử lý các con trỏ của CFString không được quản lý (hoặc NSString). Tôi đang làm việc trên một dự án CoreMIDI ngụ ý sử dụng UnsafeMutablePointer> như bạn có thể nhìn thấy trong chức năng này:Swift UnsafeMutablePointer <Unmanaged ?> Phân bổ và in

func MIDIObjectGetStringProperty(_ obj: MIDIObjectRef, 
          _ propertyID: CFString!, 
          _ str: UnsafeMutablePointer<Unmanaged<CFString>?>) -> OSStatus 

Vấn đề của tôi là tôi muốn phân bổ một bộ đệm để nhận nội dung của tài sản (_str) sau đó gọi hàm ở trên và cuối cùng in nội dung trong bảng điều khiển bằng cách sử dụng println.

Tại thời điểm này tôi đã viết này:

// Get the first midi source (I know it exists) 
var midiEndPoint : Unmanaged<MIDIEndpointRef> = MIDIGetSource(0) 

//C reate a "constant" of 256 
let buf = NSMutableData(capacity: 256) 

// Allocate a string buffer of 256 characters (I'm not even sure this does what I want) 
var name = UnsafeMutablePointer<Unmanaged<CFString>?>(buf!.bytes) 

// Call the function to fill the string buffer with the display name of the midi device 
var err : OSStatus = MIDIObjectGetStringProperty(&midiEndPoint,kMIDIPropertyDisplayName,name) 

// Print the string ... here no surprises I don't know what to write to print the content of the pointer, so it prints the address for the moment 
println(name) 

tôi không tìm thấy bất kỳ mẫu mã để sử dụng chức năng CoreMIDI trên táo developper thư viện không trên internet. Tôi thực sự bối rối vì tôi đến từ cpp và mọi thứ khác nhau rất nhanh.

EDIT:

Sau Rintaro và Martin câu trả lời tôi vẫn còn có một vấn đề, tất cả các thử nghiệm của tôi được thực hiện trên iOS 8.1 và nếu tôi sao chép mã bạn mang đến cho tôi những trình biên dịch nói với tôi rằng tôi không thể viết:

let err = MIDIObjectGetStringProperty(midiEndPoint, kMIDIPropertyDisplayName, &property) 

Kết quả trong 'Không được quản lý' không thể chuyển thành 'MIDIObjectRef'. Vì vậy, tôi đã thêm "&" vì MIDIObjectRef là UnsafeMutablePointer <void>.

let midiEndPoint = MIDIGetSource(0) 
var property : Unmanaged<CFString>? 
let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property) 

Bây giờ là: 'Switch <MIDIEndpoint>' không phải là chuyển đổi thành '@lvalue inout $ T2'. Cuối cùng tôi đã phải thay đổi lần đầu tiên để cho var, mà không hiểu tại sao?!?

var midiEndPoint = MIDIGetSource(0) 
var property : Unmanaged<CFString>? 
let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property) 

Mã bây giờ biên dịch và chạy nhưng MIDIObjectGetStringProperty trả OSStatus sai lầm -50 tương ứng với IOW hoặc từ MacErros.h:

paramErr = -50, /*error in user parameter list*/ 

Vì vậy, có vẻ như các thông số không phải là những người mà MIDIObjectGetStringProperty là đang chờ.

Nguồn "0" không tồn tại trên iPad của tôi vì MIDIGetNumberOfSources() trả về 1. Dưới đây là đoạn code hoàn chỉnh:

var numDestinations: ItemCount = MIDIGetNumberOfDestinations() 
    println("MIDI Destinations : " + String(numDestinations)) 

    for var i : ItemCount = 0 ; i < numDestinations; ++i{ 
     var midiEndPoint = MIDIGetDestination(i) 

     var property : Unmanaged<CFString>? 
     let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property) 
     if err == noErr { 
      let displayName = property!.takeRetainedValue() as String 
      println(displayName) 
     }else{ 
      println("error : "+String(err)) 
     } 
    } 

Displays:

MIDI Destinations : 1 
error : -50 

Tôi thực sự không hiểu bất cứ điều gì. ..

CẬP NHẬT:

Cuối cùng Martin tìm ra giải pháp, có vẻ như có hai định nghĩa khác nhau của MIDIObjectRef trong kiến ​​trúc 32 và 64 bit. Khi tôi chạy mã trên một iPad cũ 2 mã của tôi đã cố gắng biên dịch trong chế độ 32 bit, nơi giá trị trả về MIDIGetSource (i) không thể chuyển đổi thành MIDIObjectRef. Giải pháp là "không an toàn đúc" điểm cuối midi trên kiến ​​trúc 32 bit:

#if arch(arm64) || arch(x86_64) 
    let midiEndPoint = MIDIGetDestination(i) 
#else 
    let midiEndPoint = unsafeBitCast(MIDIGetDestination(i), MIDIObjectRef.self) 
#endif 

... Hoặc để mua thiết bị 64 bit mới ...

Cảm ơn bạn đã giúp đỡ quý báu

Trả lời

7

Tôi không có kinh nghiệm với CoreMIDI và không thể kiểm tra nó, nhưng đây là cách nó nên làm việc:

let midiEndPoint = MIDIGetSource(0) 
var property : Unmanaged<CFString>? 
let err = MIDIObjectGetStringProperty(midiEndPoint, kMIDIPropertyDisplayName, &property) 
if err == noErr { 
    let displayName = property!.takeRetainedValue() as String 
    println(displayName) 
} 

Như @rintaro nhận thấy một cách chính xác, takeRetainedValue() là lựa chọn đúng ở đây vì đó là người gọi có trách nhiệm giải phóng chuỗi. Đây là khác biệt so với quy chế quản lý bộ nhớ lõi Quỹ bình thường, nhưng được ghi lại trong MIDI Services Reference:

LƯU Ý

Khi đi qua một đối tượng cốt lõi Foundation để một chức năng MIDI, chức năng MIDI sẽ không bao giờ tiêu thụ một tham chiếu đến đối tượng. Người gọi luôn giữ lại một tài liệu tham khảo có trách nhiệm giải phóng bằng cách gọi chức năng CFRelease.

Khi nhận đối tượng Nền tảng lõi dưới dạng giá trị trả về từ hàm MIDI , người gọi luôn nhận được tham chiếu mới đối tượng, và chịu trách nhiệm giải phóng nó.

Xem "Đối tượng không được quản lý" trong "Working with Cocoa Data Types" để biết thêm thông tin.

CẬP NHẬT: Mã trên chỉ hoạt động khi biên dịch ở chế độ 64 bit. Ở chế độ 32 bit, MIDIObjectRefMIDIEndpointRef được định nghĩa là loại con trỏ khác nhau. Đây không phải là vấn đề trong (Objective-) C, nhưng Swift không cho phép chuyển đổi trực tiếp, một "dàn diễn viên không an toàn" là cần thiết ở đây:

let numSrcs = MIDIGetNumberOfSources() 
println("number of MIDI sources: \(numSrcs)") 
for srcIndex in 0 ..< numSrcs { 
    #if arch(arm64) || arch(x86_64) 
    let midiEndPoint = MIDIGetSource(srcIndex) 
    #else 
    let midiEndPoint = unsafeBitCast(MIDIGetSource(srcIndex), MIDIObjectRef.self) 
    #endif 
    var property : Unmanaged<CFString>? 
    let err = MIDIObjectGetStringProperty(midiEndPoint, kMIDIPropertyDisplayName, &property) 
    if err == noErr { 
     let displayName = property!.takeRetainedValue() as String 
     println("\(srcIndex): \(displayName)") 
    } else { 
     println("\(srcIndex): error \(err)") 
    } 
} 
+0

Tôi khẳng định làm việc này, nhưng tôi nghĩ chúng ta nên sử dụng 'takeRetainedValue() ', bởi vì trong trường hợp này, chúng ta có trách nhiệm trả về' CFString'. – rintaro

+0

@rintaro: "MIDIObjectGetStringProperty" không có "Tạo" hoặc "Sao chép" trong tên của nó. Theo các quy tắc quản lý bộ nhớ của Core Foundation, điều đó có nghĩa là người gọi không chịu trách nhiệm giải phóng bộ nhớ. Xem https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html. Tôi nghĩ rằng "Get Rule" áp dụng ở đây. –

+0

Nhưng, trên thực tế, tôi đã xác nhận rằng nó bị rò rỉ. xem: https://developer.apple.com/library/mac/qa/qa1374/_index.html – rintaro

Các vấn đề liên quan