You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迁移Metal ObjC教程至Swift时,UnsafeRawPointer转UnsafeMutableRawPointer报错求解

问题:Swift中UnsafeRawPointer转UnsafeMutableRawPointer的类型转换错误修复

我正在将Apple的《Selecting Device Objects for Compute Processing》Metal Objective-C教程增量迁移至Swift,需对接仍用Objective-C编写的代码,此时遇到报错:

Cannot convert value of type UnsafeRawPointer to specified type UnsafeMutableRawPointer

要求不修改传入函数的参数类型,该如何修复?

Swift报错代码片段

func providePositionData(_inout data: NSData) {
    // Synchronize since positions buffer will be used on another thread
    objc_sync_enter(self)
    
    let rawPtr: UnsafeMutableRawPointer = data.bytes
/* error here: Cannot convert value of type 'UnsafeRawPointer' to specified type 'UnsafeMutableRawPointer' */

    let positionsBuffer = device.makeBuffer(
        bytesNoCopy: rawPtr,
        length: data.count,
        options: .storageModeManaged,
        deallocator: nil)
    
    positionsBuffer!.label = "Provided Positions"
    
    positionsBuffer?.__didModifyRange(NSRange(location: 0, length: data.count))
    
    self.positionsBuffer = positionsBuffer
    objc_sync_exit(self)
}

可正常运行的Objective-C原代码

/// Called to provide positions data to be rendered on the next frame
- (void)providePositionData:(NSData *)data
{
    // Synchronize since positions buffer will be used on another thread
    @synchronized(self)
    {
        // Cast from 'const void *' to 'void *' which is okay in this case since updateData was
        // created with -[NSData initWithBytesNoCopy:length:deallocator:] and underlying memory was
        // allocated with vm_allocate
        void *vmAllocatedAddress = (void *)data.bytes;

        // Create a MTLBuffer with out copying the data
        id<MTLBuffer> positionsBuffer = [_device newBufferWithBytesNoCopy:vmAllocatedAddress
                                                                   length:data.length
                                                                  options:MTLResourceStorageModeManaged
                                                              deallocator:nil];

        positionsBuffer.label = @"Provided Positions";

        [positionsBuffer didModifyRange:NSMakeRange(0, data.length)];

        _positionsBuffer = positionsBuffer;
    }
}

传入NSData的Objective-C代码(内存管理逻辑)

// Wrap the memory allocated with vm_allocate with a NSData object which will allow the app to
// rely on ObjC ARC (or even MMR) to manage the memory's lifetime. Initialize NSData object
// with a deallocation block to free the vm_allocated memory when the object has been
// deallocated
{
    // Block to dealloc memory created with vm_allocate
    void (^deallocProvidedAddress)(void *bytes, NSUInteger length) =
    ^(void *bytes, NSUInteger length)
    {
        vm_deallocate((vm_map_t)mach_task_self(),
                      (vm_address_t)bytes,
                      length);
    };
    
    NSData *positionData = [[NSData alloc] initWithBytesNoCopy:positionDataAddress
                                                        length:positionDataSize
                                                   deallocator:deallocProvidedAddress];
    
    NSData *velocityData = [[NSData alloc] initWithBytesNoCopy:velocityDataAddress
                                                        length:velocityDataSize
                                                   deallocator:deallocProvidedAddress];
    
    dataProvider(positionData, velocityData, time);
}

修复方案及修正后的代码

核心修复点

Swift中NSData.bytes返回不可变的UnsafeRawPointer,对应Objective-C的const void *。由于已知底层内存是通过vm_allocate分配的可写内存(OC代码注释明确说明),可以通过UnsafeMutableRawPointer(mutating:)安全转换为可变指针,逻辑和OC里的(void *)data.bytes强制转换完全一致。

同时修正两处语法/API调用问题:

  1. 函数参数的_inout是输入错误,改为符合Swift语法的_ data: NSData
  2. 将私有API__didModifyRange替换为公开的didModifyRange方法

修正后的Swift代码

func providePositionData(_ data: NSData) {
    // Synchronize since positions buffer will be used on another thread
    objc_sync_enter(self)
    
    let rawPtr = UnsafeMutableRawPointer(mutating: data.bytes)
    
    let positionsBuffer = device.makeBuffer(
        bytesNoCopy: rawPtr,
        length: data.count,
        options: .storageModeManaged,
        deallocator: nil)
    
    positionsBuffer?.label = "Provided Positions"
    
    positionsBuffer?.didModifyRange(NSRange(location: 0, length: data.count))
    
    self.positionsBuffer = positionsBuffer
    objc_sync_exit(self)
}

说明

  • UnsafeMutableRawPointer(mutating:)是Swift官方提供的转换方式,仅在你明确知道底层内存可写时使用,这里符合OC代码的前置条件,因此是安全的。
  • 无需修改传入的NSData参数类型,完全保留原有的OC-Swift对接逻辑。

内容的提问来源于stack exchange,提问作者T.J.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 07:05:33