2016-01-13 68 views
6

我試圖將一些C代碼轉換爲swift。 (爲什麼? - 使用CoreMIDI在OS-X的情況下,你問)快速訪問固定長度C數組的元素

C代碼是這樣的

void printPacketInfo(const MIDIPacket* packet) { 
    int i; 
    for (i=0; i<packet->length; i++) { 
     printf("%d ", packet->data[i]); 
    } 
} 

而且MIDIPacket這樣定義

struct MIDIPacket 
{ 
    MIDITimeStamp   timeStamp; 
    UInt16     length; 
    Byte     data[256]; 
}; 

我的雨燕像這樣

func printPacketInfo(packet: UnsafeMutablePointer<MIDIPacket>){ 
    // print some things 
    print("length", packet.memory.length) 
    print("time", packet.memory.timeStamp) 
    print("data[0]", packet.memory.data.1) 
    for i in 0 ..< packet.memory.length { 
     print("data", i, packet.memory.data[i]) 
    } 
    } 

但是這給了一個編譯器錯誤

error: type '(UInt8, UInt8, .. cut .. UInt8, UInt8, UInt8)' has no subscript members

那麼我該如何取消引用固定大小數組的I'th元素呢?

+0

哪條線#的編譯器抱怨? – Matt

+2

這是packet.memory.data [i]行。 –

+0

packet.memory.data表示一個元組,而不是一個數組。看到我的嘗試如何解決你在我的答案麻煩。 – user3441734

回答

0

應該這樣: for i in 0 ..< packet.memory.length

是這樣? for i in 0 ..< packet.memory.data.length

+0

packet.memory.data表示一個元組...看到我的答案,我試圖將其轉換爲數組。 – user3441734

1

錯誤消息是一個提示:它顯示MIDIPacket.data不是作爲數組而是作爲元組導入的。 (是的,這是所有固定長度陣列如何導入斯威夫特。)你好像在前面的行已經注意到了這一點:

print("data[0]", packet.memory.data.1) 

元組在斯威夫特是非常靜態的,所以沒有辦法動態訪問元組元素。因此,從某種意義上說,打印數據包的唯一「安全」或慣用方式(以您暗示的方式)將是256行代碼(或最多256個,因爲數據包的length字段會告訴您它何時是安全的停止):

print("data[1]", packet.memory.data.2) 
print("data[2]", packet.memory.data.3) 
print("data[3]", packet.memory.data.4) 
/// ... 
print("data[254]", packet.memory.data.255) 
print("data[255]", packet.memory.data.256) 

顯然這不是一個好的解決方案。使用反射,每個用戶3441734的答案是一個(繁瑣的)選擇。不安全的內存訪問,根據你自己的答案(通過jckarter),是另一個(但正如API的名稱所說,它是「不安全的」)。而且,當然,您始終可以通過(Obj)C處理數據包。

如果你需要做一些超出打印包,可以延長UnsafePointer爲基礎的解決方案,將其轉換爲一個數組,像這樣:

extension MIDIPacket { 
    var dataBytes: [UInt8] { 
     mutating get { 
      return withUnsafePointer(&data) { tuplePointer in 
       let elementPointer = UnsafePointer<UInt8>(tuplePointer) 
       return (0..<Int(length)).map { elementPointer[$0] } 
      } 
     } 
    } 
} 

請注意,這裏使用了數據包的現有length財產暴露只有數據包聲稱擁有的有效字節數(而不是用零填充256元素數組的剩餘部分)的數組。這確實然而分配內存,所以它可能不利於該種你可能在使用CoreMIDI的實時運行情況。

+0

「沒有辦法動態訪問元組元素......」。我試圖做他的具體需求,在元組中的所有值都具有相同的類型。看到我的答案。 – user3441734

3

在你的情況,你可以嘗試使用這樣的事情...

// this is tuple with 8 Int values, in your case with 256 Byte (UInt8 ??) values 
var t = (1,2,3,4,5,6,7,8) 
t.0 
t.1 
// .... 
t.7 
func arrayFromTuple<T,R>(tuple:T) -> [R] { 
    let reflection = Mirror(reflecting: tuple) 
    var arr : [R] = [] 
    for i in reflection.children { 
     // better will be to throw an Error if i.value is not R 
     arr.append(i.value as! R) 
    } 
    return arr 
} 

let arr:[Int] = arrayFromTuple(t) 
print(arr) // [1, 2, 3, 4, 5, 6, 7, 8] 

...

let t2 = ("alfa","beta","gama") 
let arr2:[String] = arrayFromTuple(t2) 
arr2[1] // "beta" 
1

這是建議的https://gist.github.com/jckarter/ec630221890c39e3f8b9

func printPacketInfo(packet: UnsafeMutablePointer<MIDIPacket>){ 
    // print some things 
    print("length", packet.memory.length) 
    print("time", packet.memory.timeStamp) 
    let len = Int(packet.memory.length) 
    withUnsafePointer(&packet.memory.data) { p in 
     let p = UnsafeMutablePointer<UInt8>(p) 
     for i:Int in 0 ..< len { 
      print(i, p[i]) 
    } 
    } 
} 

這是可怕 - 我希望編譯器開啓此廢話到一些好的代碼

+1

我已經修改[我的答案](http://stackoverflow.com/a/34776819/957768)以可能有用的方式擴展此選項和其他選項。但告訴蘋果你想看到固定長度數組導入改進的最好方式是[文件錯誤](http://bugreport.apple.com),或者對[Swift開源]有貢獻( http://swift.org)社區。 – rickster

+0

斯威夫特進化列表上提出了一個處理這個問題的建議。 https://www.mail-archive.com/[email protected]/msg00885.html –