Structure as a class member in Objective C - objective-c

Is it possible a structure as a class member in objective C? If yes how can I assign values to that structure from another class?

Yes, you can. You either just expose the structure as a property (in which case you have to set/get the whole thing) or you write custom accessors that walk into the fields of the strucutre.
For a concrete example, CGRect is a structure (though it is hidden by a typdef), which means the frame property of UIView get and set a structure.
In other words:
CGRect myFrame = CGRectMake(0,0,320,480); //CGRect is a struct
myView.frame = myFrmae; //Setting a struct

You just use dot notation to assign and access the values. You can also use -> if you have a pointer to a struct.
typedef struct {
int a;
double b;
} SomeType;
// Define some class which uses SomeType
SomeType myVar;
myVar.a = 1;
myVar.b = 1.0;
SomeType* myPtr = &myVar;
NSLog (#"%i", myPtr->a);
// This works...
SomeType mySecondVar = myVar;
// But you have to be careful in cases where you have pointers rather than values.
// So this wouldn't work if either element was a C string or an array.

Yes and there is an easy way to access that struct using Objective-C 2.0 Properties. Consider the following struct from Stephens post.
typedef struct {
int a;
double b;
} SomeType;
In your .h file you would declare the member in your #interface
#interface AClass : NSObject{
SomeType member;
}
#property SomeType member;
#end
Remember that if you choose to go with pointers here you will need to manage your own memory.
And in your #implementation (your .m file) don't forget add a #synthesize
#implementation AClass
#synthesize member;
#end
I hope this helps.

Related

Should a BOOL ivar be a pointer to allow another class to set it?

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?
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.
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
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] ;
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;

What is the difference between the areas where you can declare instance variables in Objective-C? [duplicate]

Ever since starting to work on iOS apps and objective C I've been really puzzled by the different locations where one could be declaring and defining variables. On one hand we have the traditional C approach, on the other we have the new ObjectiveC directives that add OO on top of that. Could you folks helps me understand the best practice and situations where I'd want to use these locations for my variables and perhaps correct my present understanding?
Here's a sample class (.h and .m):
#import <Foundation/Foundation.h>
// 1) What do I declare here?
#interface SampleClass : NSObject
{
// 2) ivar declarations
// Pretty much never used?
}
// 3) class-specific method / property declarations
#end
and
#import "SampleClass.h"
// 4) what goes here?
#interface SampleClass()
// 5) private interface, can define private methods and properties here
#end
#implementation SampleClass
{
// 6) define ivars
}
// 7) define methods and synthesize properties from both public and private
// interfaces
#end
My understanding of 1 and 4 is that those are C-style file-based declarations and definitions that have no understanding whatsoever of the concept of class, and thus have to be used exactly how they would be used in C. I've seen them used for implementing static variable-based singletons before. Are there other convenient uses I'm missing?
My take from working with iOS is that ivars have been alost completely phased out outside of the #synthesize directive and thus can be mostly ignored. Is that the case?
Regarding 5: why would I ever want to declare methods in private interfaces? My private class methods seem to compile just fine without a declaration in the interface. Is it mostly for readability?
Thanks a bunch, folks!
I can understand your confusion. Especially since recent updates to Xcode and the new LLVM compiler changed the way ivars and properties can be declared.
Before "modern" Objective-C (in "old" Obj-C 2.0) you didn't have a lot of choices. Instance variables used to be declared in the header between the curly brackets { }:
// MyClass.h
#interface MyClass : NSObject {
int myVar;
}
#end
You were able to access these variables only in your implementation, but not from other classes. To do that, you had to declare accessor methods, that look something like this:
// MyClass.h
#interface MyClass : NSObject {
int myVar;
}
- (int)myVar;
- (void)setMyVar:(int)newVar;
#end
// MyClass.m
#implementation MyClass
- (int)myVar {
return myVar;
}
- (void)setMyVar:(int)newVar {
if (newVar != myVar) {
myVar = newVar;
}
}
#end
This way you were able to get and set this instance variable from other classes too, using the usual square bracket syntax to send messages (call methods):
// OtherClass.m
int v = [myClass myVar]; // assuming myClass is an object of type MyClass.
[myClass setMyVar:v+1];
Because manually declaring and implementing every accessor method was quite annoying, #property and #synthesize were introduced to automatically generate the accessor methods:
// MyClass.h
#interface MyClass : NSObject {
int myVar;
}
#property (nonatomic) int myVar;
#end
// MyClass.m
#implementation MyClass
#synthesize myVar;
#end
The result is much clearer and shorter code. The accessor methods will be implemented for you and you can still use the bracket syntax as before. But in addition, you can also use the dot syntax to access properties:
// OtherClass.m
int v = myClass.myVar; // assuming myClass is an object of type MyClass.
myClass.myVar = v+1;
Since Xcode 4.4 you don't have to declare an instance variable yourself anymore and you can skip #synthesize too. If you don't declare an ivar, the compiler will add it for you and it will also generate the accessor methods without you having to use #synthesize.
The default name for the automatically generated ivar is the name or your property starting with an underscore. You can change the generated ivar's name by using #synthesize myVar = iVarName;
// MyClass.h
#interface MyClass : NSObject
#property (nonatomic) int myVar;
#end
// MyClass.m
#implementation MyClass
#end
This will work exactly as the code above. For compatibility reasons you can still declare ivars in the header. But because the only reason why you would want to do that (and not declare a property) is to create a private variable, you can now do that in the implementation file as well and this is the preferred way.
An #interface block in the implementation file is actually an Extension and can be used to forward declare methods (not needed anymore) and to (re)declare properties. You could for instance declare a readonly property in your header.
#property (nonatomic, readonly) myReadOnlyVar;
and redeclare it in your implementation file as readwrite to be able to set it using the property syntax and not only via direct access to the ivar.
As for declaring variables completely outside of any #interface or #implementation block, yes those are plain C variables and work exactly the same.
First, read #DrummerB's answer. It a good overview of the whys and what you should generally do. With that in mind, to your specific questions:
#import <Foundation/Foundation.h>
// 1) What do I declare here?
No actual variable definitions go here (it's technically legal to do so if you know exactly what you're doing, but never do this). You may define several other kinds of things:
typdefs
enums
externs
Externs look like variable declarations, but they're just a promise to actually declare it somewhere else. In ObjC, they should only be used to declare constants, and generally only string constants. For instance:
extern NSString * const MYSomethingHappenedNotification;
You would then in your .m file declare the actual constant:
NSString * const MYSomethingHappenedNotification = #"MYSomethingHappenedNotification";
#interface SampleClass : NSObject
{
// 2) ivar declarations
// Pretty much never used?
}
As noted by DrummerB, this is legacy. Don't put anything here.
// 3) class-specific method / property declarations
#end
Yep.
#import "SampleClass.h"
// 4) what goes here?
External constants, as described above. Also file static variables can go here. These are the equivalent of class variables in other languages.
#interface SampleClass()
// 5) private interface, can define private methods and properties here
#end
Yep
#implementation SampleClass
{
// 6) define ivars
}
But very rarely. Almost always you should allow clang (Xcode) to create the variables for you. The exceptions are usually around non-ObjC ivars (like Core Foundation objects, and especially C++ objects if this is an ObjC++ class), or ivars that have weird storage semantics (like ivars that don't match with a property for some reason).
// 7) define methods and synthesize properties from both public and private
// interfaces
Generally you shouldn't #synthesize anymore. Clang (Xcode) will do it for you, and you should let it.
Over the last few years, things have gotten dramatically simpler. The side-effect is that there are now three different eras (Fragile ABI, Non-fragile ABI, Non-fragile ABI + auto-syntheisze). So when you see the older code, it can be a little confusing. Thus confusion arising from simplicity :D
I'm also pretty new, so hopefully I don't screw anything up.
1 & 4: C-style global variables: they have file wide scope. The difference between the two is that, since they're file wide, the first will be available to anyone importing the header while the second is not.
2: instance variables. Most instance variables are synthesized and retrieved/set through accessors using properties because it makes memory management nice and simple, as well as gives you easy-to-understand dot notation.
6: Implementation ivars are somewhat new. It's a good place to put private ivars, since you want to only expose what's needed in the public header, but subclasses don't inherit them AFAIK.
3 & 7: Public method and property declarations, then implementations.
5: Private interface. I always use private interfaces whenever I can to keep things clean and create a kind of black box effect. If they don't need to know about it, put it there. I also do it for readability, don't know if there are any other reasons.
This is an example of all kinds of variables declared in Objective-C. The variable name indicate its access.
File: Animal.h
#interface Animal : NSObject
{
NSObject *iProtected;
#package
NSObject *iPackage;
#private
NSObject *iPrivate;
#protected
NSObject *iProtected2; // default access. Only visible to subclasses.
#public
NSObject *iPublic;
}
#property (nonatomic,strong) NSObject *iPublic2;
#end
File: Animal.m
#import "Animal.h"
// Same behaviour for categories (x) than for class extensions ().
#interface Animal(){
#public
NSString *iNotVisible;
}
#property (nonatomic,strong) NSObject *iNotVisible2;
#end
#implementation Animal {
#public
NSString *iNotVisible3;
}
-(id) init {
self = [super init];
if (self){
iProtected = #"iProtected";
iPackage = #"iPackage";
iPrivate = #"iPrivate";
iProtected2 = #"iProtected2";
iPublic = #"iPublic";
_iPublic2 = #"iPublic2";
iNotVisible = #"iNotVisible";
_iNotVisible2 = #"iNotVisible2";
iNotVisible3 = #"iNotVisible3";
}
return self;
}
#end
Note that the iNotVisible variables are not visible from any other class. This is a visibility issue, so declaring them with #property or #public doesn't change it.
Inside a constructor it's good practice to access variables declared with #property using underscore instead self to avoid side effects.
Let's try to access the variables.
File: Cow.h
#import "Animal.h"
#interface Cow : Animal
#end
File: Cow.m
#import "Cow.h"
#include <objc/runtime.h>
#implementation Cow
-(id)init {
self=[super init];
if (self){
iProtected = #"iProtected";
iPackage = #"iPackage";
//iPrivate = #"iPrivate"; // compiler error: variable is private
iProtected2 = #"iProtected2";
iPublic = #"iPublic";
self.iPublic2 = #"iPublic2"; // using self because the backing ivar is private
//iNotVisible = #"iNotVisible"; // compiler error: undeclared identifier
//_iNotVisible2 = #"iNotVisible2"; // compiler error: undeclared identifier
//iNotVisible3 = #"iNotVisible3"; // compiler error: undeclared identifier
}
return self;
}
#end
We can still access the not visible variables using the runtime.
File: Cow.m (part 2)
#implementation Cow(blindAcess)
- (void) setIvar:(NSString*)name value:(id)value {
Ivar ivar = class_getInstanceVariable([self class], [name UTF8String]);
object_setIvar(self, ivar, value);
}
- (id) getIvar:(NSString*)name {
Ivar ivar = class_getInstanceVariable([self class], [name UTF8String]);
id thing = object_getIvar(self, ivar);
return thing;
}
-(void) blindAccess {
[self setIvar:#"iNotVisible" value:#"iMadeVisible"];
[self setIvar:#"_iNotVisible2" value:#"iMadeVisible2"];
[self setIvar:#"iNotVisible3" value:#"iMadeVisible3"];
NSLog(#"\n%# \n%# \n%#",
[self getIvar:#"iNotVisible"],
[self getIvar:#"_iNotVisible2"],
[self getIvar:#"iNotVisible3"]);
}
#end
Let's try to access the not visible variables.
File: main.m
#import "Cow.h"
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
Cow *cow = [Cow new];
[cow performSelector:#selector(blindAccess)];
}
}
This prints
iMadeVisible
iMadeVisible2
iMadeVisible3
Note that I was able to access the backing ivar _iNotVisible2 which is private to the subclass. In Objective-C all variables can be read or set, even those that are marked #private, no exceptions.
I didn't include associated objects or C variables as they are different birds. As for C variables, any variable defined outside #interface X{} or #implementation X{} is a C variable with file scope and static storage.
I didn't discuss memory management attributes, or readonly/readwrite, getter/setter attributes.

Is it possible to create a #property for an anonymous struct in Objective-C?

I have an anonymous struct in my code that I'd like to access via an assign #property (no pointer). However, since this is an anonymous structure. Here's the cocoa code I created (even if it's cocoa code, it's relevant to objective-c in general.)
#interface ProfileViewController : UIViewController {
struct {
BOOL isDeviceOwner:1;
} _statusFlags;
}
Now I'd like to create a property for _statusFlags:
#property (nonatomic, assign)
Yes, you just define it inline where you would define the type.
#property (nonatomic, assign) struct { ... } statusFlags;
Then when you synthesize it you can do #synthesize statusFlags = _statusFlags if you really like the underscored ivars, but this will generate the ivar for you. You do not need to define it explicitly.
You can also do it by making the property or method take a pointer to a struck, you then only have to let the compiler know that the struct exists but not what is in the struct i.e. the size, for example
struct myPrivateStruct;
...
#property(assign,nonatomic) struct myPrivateStruct * myStructProperty;
the struct myPrivateStruct then has to be then defined in your implementation file and property implement the property manually for example
struct myPrivateStruct { int a, b; float c; };
- (void)setMyStructProperty:(struct myPrivateStruct *)aValue
{
memcpy(&myIVar,aValue,sizeof(struct myPrivateStruct));
}
this is vary similar to us #class in interface files, of Objective-C class.

Objective C: Request for member XXX in something not a structure or union

I hit the error (stated in the subject) when trying to run the following code (snippet). The error is pointing to my 3rd and 4th lines of the code below.
id shape[3];
shape[0] = [[Circle alloc]init];
shape[0].fillColor = kRed;
shape[0].shapeBounds = bound0;
Prior to this set of code I had defined the enum and struct for ShapeColor and ShapeBoundary as below
typedef enum
{
kRed,
kBlue,
kGreen,
kPurple
}ShapeColor;
typedef struct
{
int x;
int y;
int width;
int height;
}ShapeBoundary;
Also, I have defined my interface and implementation of a "Circle" class
#interface Circle : NSObject
{
ShapeColor fillColor;
ShapeBoundary shapeBounds;
}
#property ShapeColor fillColor;
#property ShapeBoundary shapeBounds;
#end
#implementation Circle
#synthesize fillColor;
#synthesize shapeBounds;
#end
I used #property and #synthesize to define my getter and setter methods for "fillColor" and 'Shapebounds". Is there something wrong with the way I am using property and synthesize to cause the error in the subject? Or is there anything I am missing out. Any advise on this is greatly appreciated.
Thanks and Regards
Zhen Hoe
In order to use dot notation for properties, the class of the variable must be statically typed or cast. That is, your code must declare the class of the object instead of using id. If you used Circle *shape[3];, or ((Circle*)shape[0]).fillColor then your errors would go away. When you want your variable to be dynamically typed (using id), you need use the equivalent methods to get the properties:
id shape[3];
shape[0] = [[Circle alloc] init];
[shape[0] setFillColor:kRed];
[shape[0] setShapeBounds:bound0];
Also make sure you include the header for the Circle class in the file where you are doing this.

Cocoa Objective-c Property C structure assign fails

I want to change the variable value which is a member of a structure of another class.
But the value is not getting changed.
Here is the code.
//Structure..
typedef struct {
int a;
double b;
} SomeType;
//Class which has the structure as member..
#interface Test2 : NSObject {
// Define some class which uses SomeType
SomeType member;
}
#property SomeType member;
#end
#implementation Test2
#synthesize member;
#end
//Tester file, here value is changed..
#implementation TesstAppDelegate
#synthesize window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
Test2 *t = [[Test2 alloc]init];
t.member.a = 10;
//After this the value still shows 0
}
#end
I tried out with the below link.
Structure as a class member in Objective C
Regards,
Dhana.
To make a change to your 'member' instance variable, you need to set it in its entirety. You should do something like:
SomeType mem = t.member;
mem.a = 10;
t.member = mem;
The problem is that t.member is being used as a "getter" (since it's not immediately followed by an '='), so t.member.a = 10; is the same as [t member].a = 10;
That won't accomplish anything, because [t member] returns a struct, which is an "r-value", ie. a value that's only valid for use on the right-hand side of an assignment. It has a value, but it's meaningless to try to change that value.
Basically, t.member is returning a copy of your 'member' struct. You're then immediately modifying that copy, and at the end of the method that copy is discarded.
Make a pointer to your struct instead, then just dereference it when you want to change a part of it.
Example:
struct myStruct {
int a,
b;
};
#interface myClass : NSObject {
myStruct *testStruct;
}
#property myStruct *testStruct;
Then to change a part of myStruct just do myClassObject.testStruct->a = 55;
Change the synthesize line to:
#synthesize member = _member;
Then you can assign values in one line of code:
_member.a = 10;