Objective-C Declare Vars with ({ ... })

Declaration/definition of variables locations in ObjectiveC?

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.

Objective-C Declare vars with ({ ... })

This is a GNU (non-standard) C language extension called a “statement expression”. The syntax is supported by gcc, clang, and several other compilers.

Basically, it lets you treat an arbitrary block as a single expression, whose value is the value of the last statement in the block.

This extension is mostly useful is macro definitions. In my opinion, the code you quoted in your question (from the showFromRect:inView: method in REMenu.m) would be better if it did not use statement expressions. Instead, the code in those statement expressions should be factored out into separate methods. For example:

    self.menuWrapperView = [self newMenuWrapperView];
self.toolbar = [self newToolbar];

...

- (UIView *)newMenuWrapperView {
UIView *view = [[UIView alloc] init];
view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
if (!self.liveBlur || !REUIKitIsFlatMode()) {
view.layer.shadowColor = self.shadowColor.CGColor;
view.layer.shadowOffset = self.shadowOffset;
view.layer.shadowOpacity = self.shadowOpacity;
view.layer.shadowRadius = self.shadowRadius;
view.layer.shouldRasterize = YES;
view.layer.rasterizationScale = [UIScreen mainScreen].scale;
}
return view;
}

- (UIToolbar *)newToolbar {
UIToolbar *toolbar = [[UIToolbar alloc] init];
toolbar.barStyle = self.liveBlurBackgroundStyle;
if ([toolbar respondsToSelector:@selector(setBarTintColor:)])
[toolbar performSelector:@selector(setBarTintColor:) withObject:self.liveBlurTintColor];
toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
return toolbar;
}

How is this form of scoping called?

It is a GCC extension, called "statement expression", described at http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html.

Assigning a variable value from an Objective-C Block

You're trying to write in Objective-C with Swift syntax. The Swift example describes a lazily initialized variable, while Objective-C one declares a simple block that returns UIImageView. You'd need to call the block with

[self addSubview:thumbnailImageView()];

However, in this case using the block to initialize a variable makes little sense. If you're looking for lazily initialized properties, it would look like this in Objective-C

@interface YourClass : Superclass

@property (nonatomic, strong) UIImageView* imageView;

@end

@synthesize imageView = _imageView;

- (UIImageView*)imageView
{
if (!_imageView) {
// init _imageView here
}
return _imageView;
}

Programmatically get all frame variables in objective-c

You are basically asking to re-invent a good sized chunk of the debugger.

Without symbols, there isn't anything you can interrogate to figure out the layout of the local frame. Even with symbols, it is quite likely that the optimizer will have stomped on any local variables as the optimizer will re-use stack slots at whim once it determines the variable is no longer needed within the frame.

Note that many crashes won't be able to be caught at all or, if caught, the frame within which they occurred will have long since been destroyed.

Since you mention that you are creating a custom assertion, it sounds like you really aren't looking to introspect crashes as much as dump a snap of the local frame when you programatically detect that things have gone off the rails. While there really isn't a means of automatically reporting on local stack state, you could do something like:

{ ... some function ....
... local variables ...
#define reportblock ^{ ... code that summarizes locals ... ; return summary; }

YourAssert( cond, "cond gone bad. summary: %@", reportblock());
}

Note that the #define ensures that each YourAssert() captures the state at the time of the assertion. Note also that the above might have a potentially significant impact on performance.

Note also that I just made that code up. It seems like it is worthy of investigation, but may prove non-viable for a number of reasons.

What is the proper way to declare a global variable in Objective-C

Declaring variables inside curly braces is actually declaring an instance variable or "ivar" for short. That is, a variable that's local to instances of your class.

This used to only be possible after @interface declarations, which is why you sometimes see it there. This changed around Xcode 4 so that you can now do it after @implementation also. As far as I'm aware, this is just stylistic preference. ivars are never accessible outside a class (in theory. Technically, everything is accessible to everything in C), so defining them in the .h won't make them public. It does expose an implementation detail, though, which is why most code I see now that uses them puts them in the @implementation.

But I don't see them much in code anymore. Because when you define a @property what is actually happening under the covers is an ivar, a getter method, and a setter method are all actually being synthesized for you. The getter and setter methods just get the value of the ivar and set the value of the ivar, respectively.

So if what you want is something that has the same scope as a property, but doesn't come with the -myVar and -setMyVar: methods, then this is the right way to go.

But you probably shouldn't want that. There are a whole bunch of reasons that it's nice to only access ivars through accessor methods. It lets you override functionality, translate values, and all the other sorts of fun things abstraction affords you.

If what you want is a @property that isn't accessible outside the class, just declare it in a class extension:

//In MyClass.m
@interface MyClass()
@property NSNumber *myProperty;
@end

@implementation MyClass
//All your implementation stuff here.
@end

Because it's not in the .h file, it won't be "visible" to other classes (In theory. See above about everything being visible in C).

If on the other hand, what you really truly want is something that is really truly global (hint: you shouldn't. Global variables are generally a smell of bad design), you need to define it at the top of your file outside any @interface or @implementation blocks.

Another related tidbit: To define a "global" variable with a scope limited to a given file, look into C's static keyword. It's interesting.

Are ints always initialized to 0?

Yes, class instance variables are always initialized to 0 (or nil, NULL, or false, depending on the exact data type). See the Objective-C 2.0 Programming Language:

The alloc method dynamically allocates memory for the new object’s instance variables and initializes them all to 0—all, that is, except the isa variable that connects the new instance to its class.


EDIT 2013-05-08

Apple seems to have removed the above document (now linked to The Wayback Machine). The (currently) active document Programming With Objective-C contains a similar citation:

The alloc method has one other important task, which is to clear out the memory allocated for the object’s properties by setting them to zero. This avoids the usual problem of memory containing garbage from whatever was stored before, but is not enough to initialize an object completely.


However, this is only true for instance variables of a class; it is also true for POD types declared at global scope:

// At global scope
int a_global_var; // guaranteed to be 0
NSString *a_global_string; // guaranteed to be nil

With one exception, it is not true for local variables, or for data allocated with malloc() or realloc(); it is true for calloc(), since calloc() explicitly zeros out the memory it allocates.

The one exception is that when Automatic Reference Counting (ARC) is enabled, stack pointers to Objective-C objects are implicitly initialized to nil; however, it's still good practice to explicitly initialize them to nil. From the Transitioning to to ARC Release Notes:

Stack Variables Are Initialized with nil

Using ARC, strong, weak, and autoreleasing stack variables are now implicitly initialized with nil

In C++ (and C++ objects being used in Objective-C++), class instance variables are also not zero-initialized. You must explicitly initialize them in your constructor(s).

Objective C Global Variable

You have declared your bMajor variable as a class property. This means that you must instantiate an instance of your BeaconData class to access the variable unless you include a class method.

However, in your code I see that you also want to make these variables global. It is redundant to declare a variable as a class property and then try to make it global. In objective-c simply declaring a variable outside the implementation section will make it global for all modules that import the file with the declaration. You do it like this:

NSString *bMajor = @"Your String";

@implementation BeaconData
// YOUR CLASS CODE
@end

You're using the extern keyword incorrectly. It should be used in .h class files to let anything that imports it know that they have access to this variable. You also must declare it like I showed in the .m class file

.h looks like this:

extern NSString *bMajor;

@interface BeaconData : NSObject
@end

Just because you can do this doesn't mean you should. Based on your code I would suspect what you want to do is turn your -getData instance method into a class method for a singleton that allows the class to manage these "global" variables while keeping with good coding practice.

This SO Q/A should provide you exactly what you need to create your singleton. I recommend you do it this way.

Then in your viewController you would access these variables by getting an instance of your class using the class method.



Related Topics



Leave a reply



Submit