Формирование «UnsafeRawPointer» для переменной типа «[T]»; это, скорее всего, неверно, поскольку «T» может содержать ссылку на объект

Я унаследовал некоторый код и некоторое время пытался отключить предупреждение для Forming 'UnsafeRawPointer' to a variable of type '[T]'; this is likely incorrect because 'T' may contain an object reference.. Предупреждение относится к pointer: array в последней строке. Сам код работает или, кажется, работает, поскольку записанные байты могут быть прочитаны позже без ошибок. Но я хочу сделать это правильно. Кто-нибудь знает, о чем идет речь?

func writeBytes(pointer: UnsafeRawPointer, length: Int, documentName: String) -> Bool {
        let data = Data(bytes: pointer, count: length)
        do {
            try data.write(to: docsDir.appending(path: documentName))
            return true
        } catch {
            print("Error writing bytes for file \(documentName):", error)
            return false
        }
    }
    
func writeBytesFrom<T>(array: [T], documentName: String) -> Bool {
        return writeBytes(pointer: array, length: array.count * MemoryLayout<T>.stride, documentName: documentName)
    }

Похожий мой пост.

Sweeper 19.07.2024 14:56

На самом деле я думаю, что предупреждение вполне оправдано. Вы предполагаете, что T — тривиальный тип. Например, если T является ссылочным типом, writeBytes будет записывать ссылки (указатели) на фактические экземпляры (которые не обязательно будут «прочитаны позже без ошибок»), а не свойства каждого экземпляра. Я бы рекомендовал прояснить это в документации или что-то в этом роде.

Sweeper 19.07.2024 15:04

Помимо проблем, на которые указал Свипер, здесь существует гораздо более фундаментальная проблема. Даже для тривиальных значений (структуры/перечисления, состоящие из других тривиальных структур/перечислений), Swift не гарантирует, что расположение значений в памяти стабильно при запуске приложения, не говоря уже о между компьютерами. Например. может быть разница в целочисленном порядке байтов, 64 бит против 32 бит и т. д. Чтобы сериализовать значения в файл, вам следует использовать более преднамеренный метод сериализации, такой как JSON, YAML, XML, protobuffs и т. д.

Alexander 20.07.2024 16:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Глядя на некоторые обсуждения на forums.swift.org withUnsafePointer(to:), кажется, это способ справиться с этим.

func writeBytesFrom<T>(array: [T], documentName: String) -> Bool {
    withUnsafePointer(to: array) { pointer in
        writeBytes(pointer: pointer, length: array.count * MemoryLayout<T>.stride, documentName: documentName)
    }
}

Я думаю, ты прав, спасибо.

johnbakers 19.07.2024 14:53

Я бы предложил вместо этого использовать array.withUnsafeBtyes { pointer in ... } (документы ). Он даст вам UnsaferawBufferPointer, свойство count которого будет правильным количеством байтов (поэтому вам не нужно вручную умножать на шаг). Более того, он не полагается на особое поведение Swift по объединению массивов в указатели, что лично я считаю слишком волшебным и его следует избегать.

Alexander 20.07.2024 16:29

@Александр, проблема в том, что Data(bytes...) нужен UnsafeRawPointer, и использование array.withUnsafeBytes... дает мне ошибку Cannot convert value of type 'UnsafeRawBufferPointer' to expected argument type 'UnsafeRawPointer'

johnbakers 20.07.2024 19:39

@johnbakers Вам просто нужно использовать его свойство baseAddress

Alexander 21.07.2024 00:45

@Александр, прекрасно, спасибо, сработало

johnbakers 21.07.2024 14:24

@johnbakers Если вы это пропустили, взгляните на комментарий, который я оставил к вашему основному посту выше.

Alexander 22.07.2024 15:37

Так может быть, опубликовать более правильный ответ и отметить его как принятый вместо этого?

Joakim Danielson 22.07.2024 15:45

Вместо этого я бы предложил использовать Array.withUnsafeBtyes:

// Danger! This is really fragile!
func writeBytesFrom<T>(array: [T], documentName: String) -> Bool {
    array.withUnsafeBtyes { buffer in
        writeBytes(pointer: buffer.baseAddress, length: buffer.count, documentName: documentName)
    }
}

UnsafeRawBufferPointer, который он вам дает, будет иметь свойство count с правильным количеством байтов, предварительно рассчитанным для вас (поэтому вам не нужно вручную умножать на шаг).

Более того, он не полагается на особое поведение Swift по объединению массивов в указатели, что лично я считаю слишком волшебным и его следует избегать.


Несмотря на все вышесказанное, это все еще очень хрупкий и граничащий с неправильным кодом.

Помимо проблем, на которые указал Свипер, здесь существует гораздо более фундаментальная проблема.

Даже для тривиальных значений (структуры/перечисления, состоящие из других тривиальных структур/перечислений), Swift не гарантирует, что расположение значений в памяти стабильно при запуске приложения, не говоря уже о между компьютерами. Например. может быть разница в порядке байтов целых чисел: 64 бит против 32 бит и т. д. Чтобы сериализовать значения в файл, вам следует использовать более преднамеренный метод сериализации, такой как JSON, YAML, XML, protobuffs и т. д.

Другие вопросы по теме