2

I'm trying to convert an existing private property to an instance variable. This question is not about whether I should keep it a private property or not. I'm aware of the advantages of properties. However, in my case (at least I thought) that I don't need them.

So, the private property that I want to convert is declared as follows:

@interface Renderer ()

@property(nonatomic, strong) MTLRenderPassDescriptor* renderPassDescriptor;

@end

It is then initialized as follows:

- (void)createRenderPassDescriptor
{
  self.renderPassDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];

  if(_scaledWidth > 0 && _scaledHeight > 0)
  {
    [self createDepthBufferTexture:self.renderPassDescriptor.depthAttachment];
    [self createMultiSamplingTexture:self.renderPassDescriptor.colorAttachments[0]];
  }
}


- (void)createMultiSamplingTexture:(MTLRenderPassColorAttachmentDescriptor*)colorAttachmentDescriptor
{
  MTLTextureDescriptor* multisamplingTextureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
                                                                                                            width:(NSUInteger)_scaledWidth
                                                                                                           height:(NSUInteger)_scaledHeight
                                                                                                        mipmapped:FALSE];

  multisamplingTextureDescriptor.textureType     = MTLTextureType2DMultisample;
  multisamplingTextureDescriptor.usage           = MTLTextureUsageRenderTarget;
  multisamplingTextureDescriptor.storageMode     = MTLStorageModePrivate;
  multisamplingTextureDescriptor.resourceOptions = MTLResourceStorageModePrivate;
  multisamplingTextureDescriptor.sampleCount     = _multisampleAntiAliasingCount;

  colorAttachmentDescriptor.texture     = [self.device newTextureWithDescriptor:multisamplingTextureDescriptor];
  colorAttachmentDescriptor.loadAction  = MTLLoadActionClear;
  colorAttachmentDescriptor.storeAction = MTLStoreActionMultisampleResolve;
  colorAttachmentDescriptor.clearColor  = MTLClearColorMake(1.0f, 1.0f, 1.0f, 1.0f);
}

I have omitted createDepthBufferTexture because it does not seem relevant.

Finally, there is the renderFrame method that gets continuously invoked by the rendering loop:

- (void)renderFrame
{
  dispatch_semaphore_wait(_bufferAccessSemaphore, DISPATCH_TIME_FOREVER);

  id<CAMetalDrawable> drawable           = [self.layer nextDrawable];
  id<MTLTexture>      framebufferTexture = drawable.texture;

  self.renderPassDescriptor.colorAttachments[0].resolveTexture = framebufferTexture;

  id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];

  // rest of the rendering code
 }

I tried to convert the renderPassDescriptor property to an instance variable as follows:

@implementation Renderer
{
  MTLRenderPassDescriptor* _renderPassDescriptor;
  // other instance variables
}

At the same time, I'm removing the expression @property(nonatomic, strong) MTLRenderPassDescriptor* renderPassDescriptor;. So the property is no longer there.

After that I replace all calls of self.renderPassDescriptor with just _renderPassDescriptor. After doing so, the code compiles fine but it blows up at the following line in the renderFrame method:

_renderPassDescriptor.colorAttachments[0].resolveTexture = framebufferTexture;

Apparently, colorAttachments[0] is not nil but invoking resolveTexture crashes the app.

Unfortunately I cannot debug anymore due to Xcode not allowing me to deploy my app to physical iPhones (as described here). Running a metal app in the simulator is not supported (thanks, Apple!). So, please forgive me for not specifying what exactly is going on on that line.

Does anyone have a clue why it would make a difference whether I use a property or instance variable?

I know this might be a stupid question and comparable questions might be around already but I'm relatively new to Objective-C and just haven't figured it out myself yet.

EDIT:

My Xcode debugging issue is resolved which means I could take a closer look at what is going on.

The expression

_renderPassDescriptor.colorAttachments[0]

results in a EXC_BAD_ACCESS. So, the MTLRenderPassDescriptor* variable _renderPassDescriptor definitely behaves different than a private property of the same type. I just lack the insight why that would be the case.

ackh
  • 1,648
  • 2
  • 18
  • 36
  • Remove the line `MTLRenderPassDescriptor* _renderPassDescriptor;`. Done. The property already generates the instance variable named `_renderPassDescriptor`. – rmaddy Mar 19 '19 at 17:28
  • 1
    BTW - what benefit do you think you are getting by replacing `self.renderPassDescriptor` with `_renderPassDescriptor`? – rmaddy Mar 19 '19 at 17:29
  • It's much more about understanding why a property does not behave the same as an instance variable. But the line of though here is that there is basically no value in having a private property. I don't get "real" benefits of having a getter and setter method to access the actual value. I might as well just access the value directly without getter / setter. So I would like to remove the property and just declare an instance variable instead. I know, the runtime performance difference is minuscule. However, why not just getting rid of something I don't need (i.e. the getter / setter)? – ackh Mar 19 '19 at 20:04
  • why don't you do that then. Just get rid of the property and replace the code with instance variable – Gihan Mar 19 '19 at 20:42
  • 2
    The reason for private properties is that if you use them exclusively (i.e. `self.foo` rather than `_foo`), that when you need to add extra handling (initialize them lazy; calling some method when they're changed; add a logging statement; etc), it "just works" and you don't constantly have to audit code to say "oh, this private is supposed to be `_` and this one is supposed to be `self`." The counter-argument is that an object should know its own private properties' invariants, and if you don't, you shouldn't be touching it. I'm in the first camp, but it's a debate. – Rob Napier Mar 19 '19 at 20:46
  • @Gihan: I hope you're kidding me. This question is all about achieving precisely that. However, it does not work as expected. – ackh Mar 20 '19 at 14:56
  • When you debug does `_renderPassDescriptor` itself look like what you expect it to? Does its colorAttachments property look right to you in the debugger? In other words, is it the array indexing that crashes or accessing the things earlier in the sequence? (I believe that ARC should allow an object to live as an implied-strong ivar like this without causing you memory management issues.) – Ben Zotto Mar 20 '19 at 15:29
  • @BenZotto: When I run `_renderPassDescriptor.colorAttachments` I immediately get the EXC_BAD_ACCESS. So, array indexing is not even the problem. Its that the array itself is not properly returned. – ackh Mar 20 '19 at 16:08
  • OK. I don't think this is strictly an issue with your ivar declaration per se, since a trivial reduction of this indicates that pattern should probably work OK. I'm not specifically familiar with the Metal API. But if you see a non-nil value in the ivar that crashes on access, my suspicions lie in the directions of: possible race condition around use of the render pass descriptor that is created or exposed by using a raw ivar; semantics around ARC behavior in this pattern across threads where you're somehow tripping over an object lifetime optimization that has you looking at a released obj. – Ben Zotto Mar 21 '19 at 20:07

0 Answers0