get error when to use global Variable - ios

I have 2 class in my program
first class is class1 and second class is class2.I want create and initialize global variable in class 1 and to use in class 2 but compiler give me this ERROR XD :
Undefined symbols for architecture i386:
"_saeid", referenced from:
-[class2 viewDidLoad] in class2.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I create global variable in class1 and run that in class2 with this way but don't work:
class1.h
extern int saeid; // this is global variable
#interface class1 : UITableViewController<UITableViewDataSource,UITableViewDelegate>
#property (nonatomic,strong) IBOutlet UITableView *table;
#end
class1.m
#import "class1.h"
#import "class2.h"
#implementation class1
{
int saeid;
}
#synthesize table;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int x = (indexPath.row)+1;
saeid = x; //initialize global variable
NSLog(#"X & SAEID: %d & %d",x,saeid);
}
class2.h
#import "class1.h"
#interface class2 : UIViewController<UIScrollViewDelegate>
{
}
#end
class2.m
#import "class2.h"
#implementation class2
{
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Saeid in class2 : %d",saeid);
}

There seems to be some confusion here. Most importantly, a global variable cannot be "in" a class--global variables are by definition outside of any classes. So if you really want a global variable (more on this later) then you need to take the int saeid; definition in class1.m outside of the class definition, and just have it at the file level.
After you've done that, things still won't compile. The statement extern int saeid; roughly says to the compiler "I've defined an integer named saeid somewhere else, so just pretend it exists and let the linker figure out how to hook it up." There is no reason to have this statement in class1.h because this global variable is not used anywhere in that file. Instead, you should put this extern statement near the top of class2.m. It is used in that file, so you need to assure the compiler that the variable is defined somewhere as it is compiling that file.
Those steps should get your code to compile. But now you should stop and think about whether or not you really want a global variable. Global variables tie your classes together and make it hard to change one without affecting (and possibly breaking) others. They make it harder to test your code, and they make it more confusing to read your code. Another option to consider here is to create saeid as a property on the class1 class, and add a class1* property to class2. Then when you create your class2 instance, pass along a pointer to the existing class1 instance. The class2 instance can keep that pointer and use it to access the saeid property as needed.

In Objectice-C you can't have class variables, just instance variables.
If you want to have a global var you'd write:
#import "class1.h"
#import "class2.h"
int saeid;
#implementation class1
{
}
#synthesize table;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int x = (indexPath.row)+1;
saeid = x; //initialize global variable
NSLog(#"X & SAEID: %d & %d",x,saeid);
}
But that's just a global var, it's got nothing to do with the class!

Related

Declaring private variables in header file vs declaring variables in class extension

What's the difference between declaring a #private ivar in the header file and declaring the same ivar in the class extension without #private? As far as I understand it's the same thing.
Also, can you declare a private property in the header?
The concept is to declare in the header file only those things (methods, properties, etc) which are public. Declare all private items in the implementation file's class extension.
This provides the class users only information that is available for their use and hides all else. It also make it easier for a user of the class quickly see the functionality available to him. Writing code is all about readability and understandability to the developer.
This way a developer is free to change anything that is not exposed in the header files without making any externally visible changes.
In recent versions of Objective this is finally fully releasable via class extensions.
What's the difference between declaring a #private ivar in the header file and declaring the same ivar in the class extension without #private?
There are a few differences. In short, variables declared in the header file are visible to subclasses and class categories. Variables declared in the implementation are not.
1) Instance variables declared in a class's main #interface block are available to external class categories or extensions, even if those variables are declared #private. E.g.:
// YourClass.h
#interface YourClass : NSObject {
#private
int _yourPrivateIVar;
}
#end
// MyExtension.m
#implementation YourClass(MyExtension)
- (void)reset { _yourPrivateIVar = 0; } // This is allowed.
#end
Instance variables declared in the implementation are not available to external class categories.
2) A base class and its subclass cannot both declare the same ivar in their #interface, even if both ivars are #private. E.g., this is not allowed:
#interface Base : NSObject
{
#private
int _foo;
}
#end
#interface Subclass : Base
{
#private
int _foo; // Error: Duplicate member _foo
}
#end
If both ivars are declared in a class extension or implementation block then not only does it compile but it works as expected: both classes have their own separate _foo ivars that do not conflict with one another. On other words, both variables are truly private and separate:
#implementation Base {
int _foo;
}
#end
#implementation Subclass {
int _foo;
}
- (void)reset { _foo = 123; } // Does not affect base class's _foo
#end
Note: If the base class and subclass declare a "private" property or method with the same name it will compile without warning or error, but it will fail spectacularly at runtime as both classes unknowingly interfere with each other's private data.

iOS instance variable declaration

I would like to know what's the difference between declaring my instance variables like this:
// inside the implementation file (.m)
#interface MyCustomObject()
{
id _myIvar;
}
#end
#implementation MyCustomObject
...
#end
And like this:
// inside the implementation file (.m)
#implementation MyCustomObject{
id _myIvar;
}
...
#end
From the point of view of the USE, there is not difference.
From the point of view of the declaration, the first one is a Category:
#interface MyCustomObject()
{
}
so if you have a variable with the same name in the header file, your implementation file will see this one, but other classes whose import that header file, will see the other one.
This mechanism can be really useful to assign different attributes or properties to the same var, but differencing the exposed var, from the private internal var.

How to get the correct autocomplete in XCode for a block variable?

I have a block thats stored as an instance variable in a class
typedef void ((^didSelectWord)(NSString* word));
#property (nonatomic,strong) didSelectWord wordSelected;
and i want xcode to auto fillout the block like when you type [UIView animateWithDuration and xcode autocompletes a block for it.
When i autocomplete my block it just fills out
[self.suggestedSearchTermView setWordSelected:(didSelectWord)wordSelected
instead of
[self.suggestedSearchTermView setWordSelected:^(NSString *word) {
Is it possible to change something to make Xcode understand how to autocomplete this block?
Ok I did some testing.
Apparently you have two (far from perfect) options:
avoid the typedef and declare the property as
#property (nonatomic,strong) void (^wordSelected)(NSString * word);
As noted in the comments, this has the drawback of skipping the parameter name in the autocompletion.
explicitly add a setter declaration in the interface
typedef void ((^DidSelectWordBlock)(NSString* word));
#interface YourClass : NSObject
#property (nonatomic,strong) DidSelectWordBlock wordSelected;
- (void)setWordSelected:(DidSelectWordBlock)wordSelected;
#end
this will cause Xcode to resolve the type definition before the setter definition, giving you the nice autocompletion that you would expect. The obvious drawback is the extra setter declaration in the interface.
That said, you should fill in a bug report: http://openradar.appspot.com/
Declare your property without typedef, like this:
#property (nonatomic,strong) void (^wordSelected)(NSString *word);
With this definition Xcode would give you the expansion below:
MyClass *test = [MyClass new];
[test setWordSelected:(void (^)(NSString *))wordSelected];
In exacerbated frustration, I made a macro consolidating this gross process..
#define BlockProperty(SIGNATURE,TYPENAME,varname,Varname) typedef SIGNATURE; #property (nonatomic,copy) TYPENAME varname; - (void) set##Varname:(TYPENAME)_
Now what Previously would've required (for proper autocompletion)..
typedef void(^OnEvent)(BOOL ok,id result);
#property (nonatomic,copy) OnEvent varname;
- (void) setVarname:(OnEvent)_;
is simply
BlockProperty(void(^OnEvent)(BOOL ok, id result),OnEvent,varname,VarName);
QUITE a bit easier, less verbose, AND you get the benefit of the typedef AND and you don't have to create the unsightly, theoretically unneeded setter declaration!
If you WANT to reuse a "type" you'll need another one (which this time will only take THREE parameters (as the block type cannot be redeclared).
#define BlockProp(TYPENAME,varname,Varname) #property (nonatomic,copy) TYPENAME varname; - (void) set##Varname:(TYPENAME)_
BlockProp(OnEvent,anotherVar,AnotherVar);
You could just create a new block type (name) for each property even if their signatures match (using the first macro), but that's kind of gross. Enjoy!

Why am I getting a type conflict warning on my enum in Objective-C?

Here is my Constants.h:
#import Foundation;
typedef NS_ENUM(NSUInteger, BarcodeType) {
kNormalBarcode,
kNoBarcode,
kGenericBarcode,
kInvalidBarcode,
kComicBarcode
};
#interface Constants : NSObject
#end
And here is a function that uses it:
.h:
#interface Helper : NSObject
- (BarcodeType)barcodeType:(NSString *)barcode;
.m:
#import "Constants.h"
...
- (BarcodeType)barcodeType:(NSString *)barcode
{
return kInvalidBarcode;
}
Why am I getting this warning on my function, and what do I need to change to fix it?
Conflicting return type in implementation of 'getBarcodeType:': 'id' vs 'BarcodeType' (aka 'enum BarcodeType')
This code seemed to work fine with older versions of Xcode.
Thanks!
Check your .h file. My guess is your declaration of the method uses id, which conflicts with your definition in the .m file that returns type BarcodeType. NSEnum values aren't objects, so id isn't valid. You'll want to correct the declaration so the return type matches the implementation.

Why does self.SwipeDirection work if the property is called swipeDirection?

I have a simple ViewController derived from UIViewController to which I have added an enum property swipeDirection. In the code I normally refer to it as self.swipeDirection but in one instance I notice that I have mistakenly typed self.SwipeDirection.
If I jump to Definition I get the right variable and the code compiles and runs correctly so I am sure that the correct variable is being used.
.h file
enum EScrollDirection
{
E_SCROLL_DIRECTION_NONE = 0,
E_SCROLL_DIRECTION_LEFT,
E_SCROLL_DIRECTION_RIGHT,
E_SCROLL_DIRECTION_UP,
E_SCROLL_DIRECTION_DOWN
};
typedef enum EScrollDirection EScrollDirection;
#interface ProcessingViewController : UIViewController <UIScrollViewDelegate>
#property(nonatomic, assign)EScrollDirection swipeDirection;
#end
.m file
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
CGPoint offset = self.graphScrollView.contentOffset;
self.SwipeDirection = [self getScrollDirection:self.previousTouchPoint endPoint:self.graphScrollView.contentOffset];
// ...
}
In theory all properties are compiled into a setter method call with the following rule by default - setter name for property is setProperty: (note 1st letter of property name becoming uppercase). So both the following lines of code
self.SwipeDirection = ...
self.swipeDirection = ...
are compiled to the existing setter method
[self.setSwipeDirection:...]
and so equivalent from compiler point of view.
Note - the same does not work for (default) getter method and the following line will not compile:
NSLog(#"%d", self.SwipeDirection);

Resources