3

My class has a BOOL property that needs to be set by another class, so I am trying to use a pointer. I'm declaring a property for it like this:

@interface SomeClass : SuperClass
{
    BOOL *_shared;
}
@property(nonatomic) BOOL *shared;

Is this the correct way to do this? Then I'd simply set and access the value like this:

*self.shared = YES;

Or is the proper way to set it as a retainable property?

jscs
  • 63,694
  • 13
  • 151
  • 195
Ser Pounce
  • 14,196
  • 18
  • 84
  • 169
  • 1
    While an awful pattern to use, this is a perfectly good question. This comment is to prevent the recent spate of downvotes of questions that are valid, but are questions as to how to implement anti-patterns. – bbum May 09 '13 at 12:37
  • 1
    Indeed. Please don't downvote this question. The OP may be doing the wrong thing, but that’s different from it being a bad question. – al45tair May 09 '13 at 12:42
  • @alastair - Well, I'm kind of asking what is the right thing to do. Is what you're saying what I'm doing above is wrong, or passing a BOOL pointer between two viewControllers is wrong? – Ser Pounce May 09 '13 at 12:45
  • @StackOverFlowRider See bbum's answer below. Passing a `BOOL` pointer is almost certainly wrong. – al45tair May 09 '13 at 12:47
  • This is correct, if you allocate the memory for the `BOOL` somewhere. – Sulthan May 09 '13 at 12:59

4 Answers4

11

No, you do not want to send a pointer to an instance variable so that some other class can set the instance variable. Doing so is fragile and breaks encapsulation. It is an awful design pattern.

It is also completely unnecessary.

If Instance A can "send a pointer" to Instance B, then Instance A can easily send a reference to itself to Instance B. From there, Instance B can simply do [instanceA setShared:YES];.

@interface B:UIViewController
@property(strong) A *controllerA;
@end

@interface A:UIViewController
@property BOOL dogDoorEnabled;
@end

@implementation A
...
- (void) doSomething
{
     B *b = .... get an instance of B ...;
     [b setControllerA: self];
}
@end

@implementation B
...
- (void) doSomethingElse
{
    BOOL isCheeseOnFire = ... calculate whether the cheese is burning ...;
    [[self controllerA] setDogDoorEnabled: !isCheeseOnFire];
}
@end

(Watch out for a retain cycle -- if A somehow retains B, directly or indirectly, then the (strong) reference to A from B will create a retain cycle. Call [b setControllerA:nil] when you want to break that cycle.)

Now, if there is some reason why you still think you need to send a pointer to the internal state of A to B, please update your question.

Quinn Taylor
  • 44,553
  • 16
  • 113
  • 131
bbum
  • 162,346
  • 23
  • 271
  • 359
  • 2
    Completely agree. *Very rarely* there might be a performance-related reason to break encapsulation, but even in that case, passing `instanceA` around and using `instanceA->shared` is better than passing a pointer to a member variable. – al45tair May 09 '13 at 12:41
5

I would use

@interface SomeClass { }
@property(nonatomic) NSNumber *shared;
...
self.shared = [NSNumber numberWithBool:YES]; // in the other class
if ([self.shared boolValue]) {...} // in SomeClass where you want to find what is set
bazik
  • 609
  • 3
  • 18
  • 1
    Just a small note... you can use the new literal syntax, so could write: self.shared = @(YES); – Ian L May 09 '13 at 12:36
  • This is a good answer. Get in the habit of using NSNumber as it will make your life with CoreData much easier in the future. ;-) – Mark McCorkle May 09 '13 at 12:38
  • 5
    Converting the simple `BOOL` ivar to an `NSNumber` is completely unnecessary. This answer eliminates the anti-pattern, but doesn't really answer OP's question. – bbum May 09 '13 at 12:38
  • you're right, simple `@property (nonatomic,assign) BOOL shared;` would work just as well. – bazik May 09 '13 at 13:01
3

No. The proper way is declaring a BOOL and not a pointer to a BOOL. When you want to send the pointer to BOOL to the next viewController you can send the address of the variable with the operator &.

in your interface:

@interface SomeClass {
    BOOL _shared
}

@property (assign) BOOL _shared ;

in your implementation:

[nextViewController setPointerToBool: &_shared] ;
Gabriel
  • 3,319
  • 1
  • 16
  • 21
  • 5
    Correct about the BOOL declaration. But using the address of the instance variable as a means of editing object state is just flat out the wrong thing to do. – bbum May 09 '13 at 12:44
  • @bbum, yes it is not a smart thing to do. But it is what he has asked how to do. – Gabriel May 09 '13 at 20:02
2

As others have said, you should just use a BOOL instead of a pointer to a BOOL. Make it an assign variable, and you can simply assign to it and read it directly. Also, In the modern compiler you don't need to declare instance variables, and it seems to be a good practice not to.

@interface SomeClass

@property (assign) BOOL shared;

@end

In your implementation:

self.shared = YES;

When it comes to your view controller, instead of passing a pointer to the BOOL, just pass a pointer to the instance of SomeClass, and set it like this:

someInstance.shared = YES;
paulmelnikow
  • 16,895
  • 8
  • 63
  • 114