12

I'm trying to declare some instance variables for a custom button class in Objective-C (for iOS):

@interface PatientIDButton : UIButton {
    NSUInteger patientID;
    NSString * patientName;
}
@end

However, these are now private and I need them accessible to other classes. I guess I could make accessor functions for them, but how would I make the variables themselves public?

Cœur
  • 37,241
  • 25
  • 195
  • 267
easythrees
  • 1,530
  • 3
  • 16
  • 43
  • 3
    FYI, making ivars public is very unidiomatic and depending on whether you are using ARC can greatly complicate your memory management. – Chuck Jul 07 '13 at 02:52
  • 1
    What @chuck said. Direct access to instance variables is a really bad pattern to use. Breaks encapsulation and defeats things like KVO. – bbum Jul 07 '13 at 03:03
  • You really shouldn't be using explicit ivars at all. Apple, as I understand, now encourages (and themselves use) properties exclusively. And with implicit synthesizing, they're trivial and powerful. – Kevin Jul 07 '13 at 03:14

1 Answers1

19

To make instance variables public, use @public keyword, like this:

@interface PatientIDButton : UIButton {
    // we need 'class' level variables
    @public NSUInteger patientID;
}
@end

Of course you need to remember all the standard precautions of exposing "raw" variables for public access: you would be better off with properties, because you would retain flexibility of changing their implementation at some later time.

Finally, you need to remember that accessing public variables requires a dereference - either with an asterisk or with the -> operator:

PatientIDButton *btn = ...
btn->patientID = 123; // dot '.' is not going to work here.
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 1
    This seems way more complicated than needed. Why not just declare a public property in the header file? `@property NSUInteger patientID`. Then each instance of the button can be access through standard Obj-C methods. myButton.patientID. – Dan Fairaizl Jul 07 '13 at 02:52
  • 1
    Yes, a property makes sense as well. Thanks all! – easythrees Jul 07 '13 at 03:06
  • Do not use the -> operator to access ivars. – bbum Jul 07 '13 at 03:07
  • 3
    @bbum Why, should `(*btn).patientID` be used instead? – Sergey Kalinichenko Jul 07 '13 at 03:08
  • @dasblinkenlight No -- you shouldn't be assigning directly to instance variables at all outside of the class's implementation itself (where you don't need to use `->` at all). Going directly breaks encapsulation. – bbum Jul 07 '13 at 14:39
  • @bbum Ah, I see your point. I agree, one should avoid exposing "raw" variables. I do not understand why the designers of Objective-C added this feature in the first place. – Sergey Kalinichenko Jul 07 '13 at 14:53
  • 1
    @dasblinkenlight: When Objective-C was created, it was a very different world. It was originally a tiny Smalltalk-like object system on top of C, very much like C With Classes (which evolved into C++). There was no NSObject, there wasn't even any retain or release, and the overhead of message calls was considered rather decadent. – Chuck Jul 07 '13 at 22:34
  • @bbum and in the context of tests, sometimes you want to test if custom getters or setters are doing the right thing related to the ivar, so what do you recommend? – Diogo T Sep 01 '15 at 22:51