此 Objective-C 方法中代码块的用途

问题描述 投票:0回答:1

我是目标 C 的新手,并且对来自 Apple 的这个示例项目 展示一些 Metal 特性的代码有疑问。

代码包含位于函数范围内的几个块。在每个块内部,分配一些资源,并将分配的资源传递给各种方法。

在函数内的块内这样做的原因是什么?

另外,我可以看到在每个块内声明的变量正在块范围之外消失,但是如何为这些变量指向的资源管理内存?它是由自动释放池管理的吗?

- (void)loadMetal
{
    NSError* error = nil;
    NSLog(@"Selected Device: %@", _mtlDevice.name);
    _mtkView.colorPixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
    _mtkView.depthStencilPixelFormat = MTLPixelFormatDepth32Float;
    _commandQueue = [_mtlDevice newCommandQueue];

    id<MTLLibrary> defaultLibrary = [_mtlDevice newDefaultLibrary];

    // Create the render pipeline to shade the geometry.
    {
        id<MTLFunction> vertexFunc   = [defaultLibrary newFunctionWithName:@"vertexShader"];
        id<MTLFunction> fragmentFunc = [defaultLibrary newFunctionWithName:@"fragmentShader"];

        MTLRenderPipelineDescriptor* renderPipelineDesc = [MTLRenderPipelineDescriptor new];
        renderPipelineDesc.vertexFunction = vertexFunc;
        renderPipelineDesc.fragmentFunction = fragmentFunc;
        renderPipelineDesc.vertexDescriptor = nil;
        renderPipelineDesc.colorAttachments[0].pixelFormat = _mtkView.colorPixelFormat;
        renderPipelineDesc.depthAttachmentPixelFormat = _mtkView.depthStencilPixelFormat;
        // means "i don't need a depth buffer"
        renderPipelineDesc.stencilAttachmentPixelFormat = MTLPixelFormatInvalid;

        _renderPSO = [_mtlDevice newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&error];
        NSAssert(_renderPSO, @"Failed to create forward plane with sparse texture render pipeline state");
    }

    // Create the default depth stencil state for the depth test.
    {
        MTLDepthStencilDescriptor* desc = [MTLDepthStencilDescriptor new];
        desc.depthWriteEnabled = YES;
        desc.depthCompareFunction = MTLCompareFunctionLess;
        _depthStencilState = [_mtlDevice newDepthStencilStateWithDescriptor:desc];
    }

    // Prefill the render pass descriptors with the clear, load, and store actions.
    {
        _renderPassDescriptor = [MTLRenderPassDescriptor new];
        _renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.1, 0.1, 0.1, 1.0);
        _renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
        _renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
        _renderPassDescriptor.depthAttachment.clearDepth = 1.0;
        _renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear;
        _renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionDontCare;
    }
}
objective-c objective-c-blocks
1个回答
0
投票

在函数内的块内这样做的原因是什么?

首先你应该区分 Objective-C 块,它们是 Objective-C 中仿函数的语法糖(可以执行某些任务的一流对象),具有以下语法:

^{
    NSLog(@"Objective-C block");
}

匿名块,继承自C并引入作用域:

{
   printf("Anonymous block");
}

在给定的代码中,它是一个匿名块,它的主要好处是它有助于稍微解耦代码,即在块内引入的变量在块外是不可见的。如果您启用了 ARC,另一个副作用是编译器确保在作用域末尾释放所有本地非保留对象(但不一定释放)。

这对于最后一段代码来说似乎有些多余,省略匿名块不会改变函数在这里的工作方式:

// Prefill the render pass descriptors with the clear, load, and store actions.
{
    _renderPassDescriptor = [MTLRenderPassDescriptor new];
    _renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.1, 0.1, 0.1, 1.0);
    _renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
    _renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
    _renderPassDescriptor.depthAttachment.clearDepth = 1.0;
    _renderPassDescriptor.depthAttachment.loadAction = MTLLoadActionClear;
    _renderPassDescriptor.depthAttachment.storeAction = MTLStoreActionDontCare;
}

..但它仍然为读者提供了代码不同部分的清晰视觉分离。


另外,我可以看到在每个块内声明的变量都在块范围之外消失

如果您指的是这些部分:

...
// Create the render pipeline to shade the geometry.
{
    ...
    _renderPSO = [_mtlDevice newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&error];
    NSAssert(_renderPSO, @"Failed to create forward plane with sparse texture render pipeline state");
}

// Create the default depth stencil state for the depth test.
{
    ...
    _depthStencilState = [_mtlDevice newDepthStencilStateWithDescriptor:desc];
}
...

..那么传递参数的函数实际上可以保留对象,但在 Objective-C 中这里没有争议:most 语言中的对象是动态分配的,因此它们可以超过声明的范围in. 通常 ARC 会确保所有引用对象的变量都是有效的,只要它们是可寻址的:

- (void)foo {
    NSObject *obj;
    {
        NSObject *localObj = [NSObject new];
        obj = localObj;
    }
    // The `obj` have the `localObj` retained here, so it keeps on living
    NSLog(@"%@", obj);
    // `obj` is released at the of the scope it was declared in;
}

在幕后,ARC 的作用可以解读如下:

- (void)foo {
    NSObject *obj;
    {
        NSObject *localObj = [NSObject new];
        obj = [localObj retain];
        [localObj release];
    }
    // The `obj` have the `localObj` retained here, so it keeps on living
    NSLog(@"%@", obj);
    // `obj` is released at the of the scope it was declared in;
    [obj release];
}
© www.soinside.com 2019 - 2024. All rights reserved.