Преобразование UnsafeMutableRawPointer в строку (utf8) в быстром - PullRequest
1 голос
/ 24 мая 2019

Вопрос прост Как конвертировать UnsafeMutableRawPointer? в String(encoding: utf8) в swift.

Я получаю некоторые данные из сокета, написанного в obj c, класс модели выглядит как

@interface PTData : NSObject
@property (readonly) dispatch_data_t dispatchData;
@property (readonly) void *data;
@property (readonly) size_t length;
@end

Соответствующий код obj c для преобразования данных в строку

PTExampleTextFrame *textFrame = (PTExampleTextFrame*)payload.data;
textFrame->length = ntohl(textFrame->length);
NSString *message = [[NSString alloc] initWithBytes:textFrame->utf8text length:textFrame->length encoding:NSUTF8StringEncoding];

Здесь PTExampleTextFrame является struct

typedef struct _PTExampleTextFrame {
  uint32_t length;
  uint8_t utf8text[0];
} PTExampleTextFrame; 

Но я не могу преобразовать код в swift. Но когда я попытался преобразовать код выглядит,

let data = Data(bytesNoCopy: payload!.data, count: payload.length,deallocator: .none)

let text = String(bytes: data, encoding: String.Encoding.utf8)

Каким-то образом я получил ответ, но к тексту добавляется несколько escape-символов.

hi составляет \0\0\0\u{02}jj

long text до \0\0L\u{1D}long text

Я не понял понятия UnsafeMutableRawPointer и что это за префиксы.

1 Ответ

2 голосов
/ 24 мая 2019

Если ваш код obj c для преобразования данных в строку подтвержден для правильной работы, я рекомендую вам написать расширение Objective-C для работы со Swift.

Например:

PTData + Swift.h

#import <Foundation/Foundation.h>

@class PTData;

NS_ASSUME_NONNULL_BEGIN

@interface PTData (Swift)
@property (readonly) NSString *message;

@end

NS_ASSUME_NONNULL_END

PTData + Swift.m

#import "PTData.h"
#import "PTData+Swift.h"

@implementation PTData (Swift)

- (NSString *)message {
    PTExampleTextFrame *textFrame = (PTExampleTextFrame*)self.data;
    uint32_t length = ntohl(textFrame->length);
    NSString *message = [[NSString alloc] initWithBytes:textFrame->utf8text
                                                 length:length
                                               encoding:NSUTF8StringEncoding];
    return message;
}

@end

{YourProject} -Bridging-header.h

#import "PTData.h"
#import "PTData+Swift.h"

(Вам может потребоваться изменить #import "PTData.h", чтобы включить фактические заголовки.)

С помощью вышеуказанного расширения вы можете просто написать в Swift:

debugPrint(payload.message)

В противном случае, если вы решитесь настаивать на написании Swift, эквивалентного вашему obj c коду для преобразования данных в строку , показанный вами код Swift будет слишком коротким.

extension PTData {
    var textFrameMessage: String {
        let textFrame = self.data.assumingMemoryBound(to: PTExampleTextFrame.self)
        let length = Int(textFrame.pointee.length.bigEndian)
        let utf8text = self.data
            .advanced(by: MemoryLayout<UInt32>.size) // <- Sadly enough, `MemoryLayout.offset(of:)` does not work as expected for `utf8text`
            .assumingMemoryBound(to: UInt8.self)
        let bytes = UnsafeBufferPointer(start: utf8text, count: length)
        let message = String(bytes: bytes, encoding: .utf8)! // <- This may crash, if the message is not encoded in UTF-8
        return message
    }
}

debugPrint(payload.textFrameMessage)

Я тестировал вышеуказанные коды с минимальными оценочными данными, но они могут отличаться от фактических данных, которые вы получаете. Пожалуйста, попробуйте и скажите мне, если что-то не так.

...