2014-09-07 4 views
0

Я разрабатываю пошаговую игру с быстрым, где все должно быть преобразовано в NSData. Прямо сейчас я застрял в «NS-stuff» в течение многих дней. Поскольку CGPoint не является объектом, а структурой, он не может быть напрямую преобразован в NSData, а также CGFloat внутри CGPoint. То, что я пытаюсь сделать, это: (Просто идея, не уверен, если это работает пока.)Каков наилучший способ транспортировки CGPoint между устройствами?

  1. новообращенный CGPoint к 2 различным поплавков
  2. создать NSNummer с поплавком
  3. создать NSData с NSNumber
  4. конвертировать NSData обратно в NSNumber в другом устройстве
  5. конвертировать NSNumber в Float
  6. объединить их обратно CGPoint

Этот способ слишком сложный. Есть ли лучший способ реализовать его или какие-либо рекомендации? Заранее спасибо!!!

PS: NSKeyedArchiver НЕ следует рассматривать из-за его производительности. (Не уверен!)

+0

Хотя вы можете считать это «слишком сложным» и другие любезно предложенные альтернативы, решение, которое вы описываете, в порядке. – 2014-09-09 01:59:22

ответ

1

Примечание: если вам не нужна высокая производительность, вы, вероятно, лучше согласитесь с предложением Роба Напира (NSStringFromCGPoint/CGPointFromString), поскольку его проще и легче отлаживать. Тем не менее, многие игры имеют высокие требования к производительности и нуждаются в более чем одном CGPoint за игровой цикл. Вот мои предположения.

Предполагая CGFloat того же типа (32-битные или 64-бит) на обоих отправителя и получателя:

var pointToSend = CGPointMake(100, 200) 
let data = NSData(bytes: &pointToSend, length: sizeof(CGPoint)) 
// send data to other device 

// receive data on other device 
if (data.length == sizeof(CGPoint)) { 
    var receivedPoint = UnsafePointer<CGPoint>(data.bytes).memory 
} else { 
    // error 
} 

Если приемника CGFloat может отличаться от отправителя:

typealias DoublePoint = (x: Double, y: Double) 

// sender 
var pointToSend = CGPointMake(100, 200) 
var pairToSend = (Double(pointToSend.x), Double(pointToSend.y)) 
let data = NSData(bytes: &pointToSend, length: sizeofValue(pairToSend)) 

// receiver 
if (data.length == sizeof(DoublePoint)) { 
    var receivedPair = UnsafePointer<DoublePoint>(data.bytes).memory 
    var receivedPoint = CGPointMake(CGFloat(receivedPair.x), CGFloat(receivedPair.y)) 
} else { 
    // error 
} 
+0

спасибо. Это работает хорошо. Теперь я изучаю «UnsafePointer», чтобы узнать, почему он называется «небезопасным». :) – Sifeng

+1

Это небезопасно по нескольким причинам. Он не обеспечивает управление памятью, поэтому, если основной объект уходит, он может стать обвисшим указателем (этого не может быть здесь, потому что указатель немедленно уничтожается). Это также небезопасно, потому что оно обходит безопасность типов. Если 'data.bytes' были слишком коротки, например, вы читали бы здесь недопустимую память и могли бы сработать.Если 'data' фактически не указывает на' CGPoint', вы можете прочитать мусор (что не так важно для CGPoint'а, но может испортить другие виды объектов). Не сказать, что этот ответ бесполезен; это просто не безопасно. –

+1

'UnsafePointer' позволяет вам делать небезопасные вещи (например, сбой вашей программы или повреждение вашей кучи), поскольку она обходит систему типов и систему подсчета ссылок. Как и любой мощный инструмент, вы можете использовать его безопасно. Я обновил свой ответ, чтобы сделать его более безопасным. –

3

Простейший способ кодирования CGPoint использует NSStringFromCGPoint и CGPointFromString. Это избавит вас от всех 32/64-разрядных проблем, с которыми вам пришлось столкнуться.

Транспорт это очень дешево (менее одного MTU, так что это не имеет значения). Единственное, что может стоить дорого, это синтаксический анализ строк, который почти наверняка перегружен из-за затрат на его проводку.

Но если у вас есть очень жесткий сетевой протокол и нуждаются в максимальной производительности, я бы превратить CGPoint в (Float32, Float32), или еще лучше, (Int32, Int32) если вы на самом деле не нужны, не только целые значения. Это легко кодировать, поскольку @robmayoff предлагает, исходя из предположения, что вы не заботитесь о контенте. Вместе с Int вы можете легко использовать Int.bigEndian и Int(bigEndian:), чтобы справиться с этим.

+0

спасибо. Я тоже попробую. (У) – Sifeng