Why I am getting "Apple Mach -O Linker error"? - objective-c

I have two UIViewControllers. They have two variables with the same names but in different files.
HomeViewController.h
#import <UIKit/UIKit.h>
#interface HomeViewController : UIViewController
#end
HomeViewController.m
#import "HomeViewController.h"
#import "DetailViewController.h"
#interface HomeViewController ()
#end
#implementation HomeViewController
bool search=true;
bool dbOpen=false;
....
#end
DetailViewController.h
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController
#end
DetailViewController.m
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
bool search=true;
bool dbOpen=false;
....
#end
When I remove "search" and "dbOpen" variables from HomeViewController.m or DetailViewController.m files, it compiles successfully. Why this is happening? Variables are not in header files and m files don't know about each other?

Global variables (what you have) are global, it doesn't matter if they are in different files (also what makes them dangerous).
bool search;
A global can only be defined once or you will get a linker error. Also people will avoid you at social events.
Static variables are per file - this might have been what you meant..
static bool search;
Instance variables are per instance. This is probably what you meant. You should start by using Properties - the compiler will handle adding the instance variable that backs it.
Something along the lines of:
#property bool search;
I'm trusting that you mean to use bool and not the Objective-c type BOOL. Visibility is up to you. Define the property in the Interface if you want it to be public.
If you really don't want a property you should define your instance variables in the interface section.
#interface HomeViewController : UIViewController {
bool search;
}
#end
Just to make it more confusing.. If you really must define the Instance variables in the Implementation there is a way, but I can't bring myself to type it.

The variable declarations have to be in the #interface like:
#interface HomeViewController ()
BOOL search;
BOOL dbOpen;
#end
and
#interface DetailViewController ()
BOOL search;
BOOL dbOpen;
#end
To set their initial values add the assignment in for exam,e viewDidLoad
- (void)viewDidLoad
{
search = YES;
dbOpen = NO;
}
Note the other changes like BOOL and YES/NO.

Since you have declared these variables
bool search=true;
bool dbOpen=false;
as global, only one occurance of these variables can exist. Change the name of the global variables in "HomeViewController.m" or "DetailViewController.m"

This is classical error of using global variables. Try to avoid to use it. In general use the extern keyword.
You use extern with global variables to create unambiguous
declarations. In addition to helping the compiler, it also clues in
anyone reading the code that the global variable is defined (and
possibly initialized) elsewhere, but you're simply using it here
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
extern bool search=true;
extern bool dbOpen=false;
....
#end

Related

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

So, I was wondering what the proper way to declare a global variable is in an iOS Project.
I don't want it set as a property, because the variable should not be accessible from outside the class.
I am going to provide a few ways I have seen, let me know which is the proper way, and if there is another way that is better.
This way I add the global variable inside curly braces after the #interface declaration in the implementation file .m. Then I can initialize the variable in the viewDidLoad
#import "ViewController.h"
#interface ViewController () {
int globalVariableTest;
}
#end
#implementation ViewController
Another way I add the global variable inside curly braces after the #implementation declaration in the implementation file .m. Again intializing in the viewDidLoad
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController {
int globalVariableTest;
}
Another way is adding the variable after the #implementation without the curly braces, also this allows me to set the intial value without the viewDidLoad
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
int globalVariableTest = 1;
Another way is to add the variable after the #interface inside the header file .h
#interface ViewController : UIViewController
{
int globalVariableTest;
}
So if there is a better way please let me know, all help will be appreciated!
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.
You can use a singleton class to create/share (read / write) all variables across different classes (view controller).
.h
#interface SharedVariables : NSObject {
NSDictionary *dicti_StackSites;
NSDictionary *dicti_UserMe;
}
#property(nonatomic, strong) NSDictionary *dicti_StackSites;
#property(nonatomic, strong) NSDictionary *dicti_UserMe;
+(id)sharedVariablesManager;
#end
SharedVariables.m
#import "SharedVariables.h"
#implementation SharedVariables
#synthesize dicti_StackSites;
#synthesize dicti_UserMe;
+(id)sharedVariablesManager {
static SharedVariables *sharedVariablesClass = nil;
#synchronized(self) {
if (sharedVariablesClass == nil) {
sharedVariablesClass = [[self alloc] init];
}
}
return sharedVariablesClass;
}
-(id)init {
if (self = [super init]) {
dicti_StackSites = [[NSDictionary alloc] init];
dicti_UserMe = [[NSDictionary alloc] init];
}
return self;
}
-(void)dealloc {
}
#end
Usage from any other class
#import "SharedVariables.h"
SharedVariables *sharedManager = [SharedVariables sharedVariablesManager];
//to get sharedManager.dicti_StackSites
//to set sharedManager.dicti_StackSites = ...

Modern Objective-C and #synthesize

I'm trying convert my code to Modern Objective-C style. How i read here http://www.techotopia.com/index.php/The_Basics_of_Modern_Objective-C": "In the case of Modern Objective-C, however, the synthesis takes place by default, making the use of #synthesize declarations unnecessary. When using default property synthesize, instance variable properties are accessible from within code using the property name prefixed with an underscore."
However, I have:
Relationship.h
#interface Relationship : NSObject <NSCoding>
//...
#property(nonatomic, weak) Person* first;
//...
#end`
OtherRelationship.h
#import "Relationship.h"
#interface OtherRelationship : Relationship
#end
OtherRelationship.m
#import "OtherRelationship.h"
#implementation OtherRelationship
#synthesize first = _first;
- (void)foo
{
NSLog(#"%#", _first);
}
and it's working. But when i delete
#synthesize first = _first;
i get "Use of undeclared identifier '_first'" error. Does inheritanced variables doesn't work with autosynthesize or should i looking for problem elsewhere?
The backing ivar in the superclass is #private to the subclass. That is, the subclass may call self.first, but not _first. If you want to #synthesize again, use a different name because you can't refer to _first. For example, replace with #synthesize first = _ffirst; or just drop the #synthesize.

.h instance variable declaration

I'm having a hard time understanding why the following textfield is declared twice in some tutorials.
In the .h file:
# include <UIKit/UIKit.h>
#interface MyViewController : UIViewController {
UITextField *name; // <----- What do I need this for? Is it the same as below?
}
#property (nonatomic, strong) IBOutlet UITextField *name; // <----- Same as this?
#end
At first I thought this would be something like an instance variable, but they are only declared here in the .m file, right?
.m file
#import "MyViewController.h"
#implementation UIViewController {
NSString *myString; // <----- This is an instance variable, right?
}
What's the "UITextField *name;" for? Don't I only need the second one with the #property in front? Thank you.
This is an old way, just use property is OK.
If you declare both, you must use #synthesize name; in your .m file to make self.name same as name.
XCode4.2 auto synthesize name = _name. So use self.name as much as possible in your .m file.
Variable in {} just use for internal or private, when you don't want implement setter and getter.
If you are targeting iPhone OS or 64-bit Mac OS X then you do not need to define ivars for your properties. Take a look at Dynamic ivars: solving a fragile base class problem

How to simulate protected properties and methods in objective-c [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Protected methods in objective-c
The way to declare private properties is simple.
You declare that in extension that's declared in .m files.
Say I want to declare protected properties and access it from the class and subclass.
This is what I tried:
//
// BGGoogleMap+protected.h
//
//
#import "BGGoogleMap.h"
#interface BGGoogleMap ()
#property (strong,nonatomic) NSString * protectedHello;
#end
That one is compile. Then I added:
#import "BGGoogleMap+protected.h"
#implementation BGGoogleMap ()
-(NSString *) protectedHello
{
return _
}
#end
Problem starts. I can't implement class extension outside the original .m files it seems. Xcode will demand something inside that bracket.
If I do
#import "BGGoogleMap+protected.h"
#implementation BGGoogleMap (protected)
-(NSString *) protectedHello
{
return _
}
#end
I cannot access the ivar of _protectedHello declared in BGGoogleMap+protected.h
Of course I can use regular category rather than extension, but that means I can't have protected properties.
So what should I do?
The Objective-C Programming Language says this:
Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main #implementation block for the corresponding class.
So you could just implement your class extension's methods in the class's main #implementation. That is the simplest solution.
A more complicated solution is to declare your “protected” messages and properties in a category, and declare any instance variables for that category in a class extension. Here's the category:
BGGoogleMap+protected.h
#import "BGGoogleMap.h"
#interface BGGoogleMap (protected)
#property (nonatomic) NSString * protectedHello;
#end
Since a category cannot add an instance variable to hold protectedHello, we need a class extension also:
`BGGoogleMap_protectedInstanceVariables.h'
#import "BGGoogleMap.h"
#interface BGGoogleMap () {
NSString *_protectedHello;
}
#end
We need to include the class extension in the main #implementation file so that the compiler will emit the instance variable in the .o file:
BGGoogleMap.m
#import "BGGoogleMap.h"
#import "BGGoogleMap_protectedInstanceVariables.h"
#implementation BGGoogleMap
...
And we need to include the class extension in the category #implementation file so that the category methods can access the instance variables. Since we declared the protectedHello property in a category, the compiler will not synthesize the setter and getter method. We have to write them by hand:
BGGoogleMap+protected.m
#import "BGGoogleMap+protected.h"
#implementation BGGoogleMap (protected)
- (void)setProtectedHello:(NSString *)newValue {
_protectedHello = newValue; // assuming ARC
}
- (NSString *)protectedHello {
return _protectedHello;
}
#end
Subclasses should import BGGoogleMap+protected.h to be able to use the protectedHello property. They should not import BGGoogleMap_protectedInstanceVariables.h because the instance variables should be treated as private to the base class. If you ship a static library without source code, and you want users of the library to be able to subclass BGGoogleMap, ship the BGGoogleMap.h and BGGoogleMap+protected.h headers, but don't ship the BGGoogleMap_protectedInstanceVariables.h header.
I wish I could tell you otherwise but you just can't. See this question for more information: Protected methods in Objective-C.
I am not sure, what you want to do? Something Hacking or Cracking of Data Abstraction out of OOPS concept?
Extensions are used to add properties. You have successfully added private property as in
#import "BGGoogleMap.h"
#interface BGGoogleMap ()
#property (strong,nonatomic) NSString * protectedHello;
#end
What are you doing in this ?
#import "BGGoogleMap+protected.h"
#implementation BGGoogleMap ()
-(NSString *) protectedHello
{
return _
}
#end
You have extended a class, now you are again implementing same class !!! Twice!!! And category only comes with .h file. I guess you are creating yourself a .m file, that not acceptable.
Private properties cant be accessed outside the class, it can be accessed only from the base class or subclass. That is what the error is.
I can't implement class extension outside the original .m files it seems.
Yes this is abstraction and data hiding of Objective-c !!!

Dynamically typed class generates compiler warnings on method selection

Perhaps this is the wrong way to go about this, but it seems like such a clean and workable approach that I wonder how I can make the compiler warning go away?
#interface SomeView : UIView {
NSString *stringOfsomeImportance;
RelatedClass *niftyService;
}
#property (nonatomic, copy) NSString * stringOfnoImportance;
#property (nonatomic, retain) RelatedClass *niftyService;
#implementation
-(void)someMethod;
-(void)otherMethods;
#implementation RelatedClass *pvSomeObj = [[RelatedClass alloc] initWithSender:self];
[self setNiftyService:pvSomeObj];
Now, looking at the RelatedClass implementations...
#interface RelatedClass : NSObject {
id thesender;
#property (nonatomic, retain) id thesender;
#implementation
[thesender otherMethods]; // this generates a compiler warning
// that otherMethods cannot be found
// in SomeView, though it *is* found
// and seems to execute just fine
This seems like a valid approach, so I'm left wondering why the warning?
Is there a way to better "explain" this to the compiler?
Could someone kindly share if this type of linkage is encouraged or if there is a better way to link two related, interdependent classes that need to communicate with one another?
I can't statically declare the sender object (SomeView) in RelatedClass because that seems to cause a recursion problem, as SomeView is defined with RelatedClass as a member...
Any suggestions?
You can define a protocol and say that your thesender object must conform to it:
#protocol MyProtocol
-(void)otherMethods;
#end
#interface RelatedClass : NSObject {
id<MyProtocol> thesender; // Now compiler knows that thesender must respond
// to otherMethods and won't generate warnings
}
You can send otherMethods message another way (you may need to define theSender as NSObject here):
if ([theSender respondsToSelector:#selector(otherMethods)])
[theSender performSelector:#selector(otherMethods)];
Edit: Actually you can also define thesender as SomeView* in your RelatedClass using forward class declaration:
//SomeView.h
#class RelatedClass;
#interface SomeView : UIView {
RelatedClass *niftyService;
}
// then include RelatedClass.h in SomeView.m
//RelatedView.h
#class SomeView;
#interface RelatedClass : NSObject {
SomeView* thesender;
}
// then include SomeView.h in RelatedClass.m
In your headers, you can forward declare classes that you want to use. In your implementation files, you can include the full header of those classes that you forward-declared.
For example:
SomeView.h
#import <FrameworkHeader.h>
// Here, you are saying that there is a class called RelatedClass, but it will be
// defined later.
#class RelatedClass;
#interface SomeView : UIView
{
RelatedClass *niftyService;
}
#end
SomeView.m
#import "SomeView.h"
#import "RelatedClass.h"
// By including "RelatedClass.h" you have fulfilled the forward declaration.
#implementation SomeView
// Can use "RelatedClass" methods from within here without warnings.
#end
RelatedClass.h
#import <FrameworkHeader.h>
#class SomeView;
#interface RelatedClass
{
SomeView *someView;
}
// methods
#end
RelatedClass.m
#import "RelatedClass.h"
#import "SomeView.h"
#implementation RelatedClass
// Can use "SomeView" methods from within here without warnings.
#end
id thesender = ....;
[thesender otherMethods]; // this generates a compiler warning
// that otherMethods cannot be found
// in SomeView, though it *is* found
// and seems to execute just fine
For the above to generate the warning as you describe, it is entirely because the method -otherMethods has not been declared someplace where the compiler sees the declaration before attempting to compile the call site.
That is, the declaration of the method:
- (void) otherMethods;
Must appear in a header file that is imported -- directly or indirectly -- by the implementation file compiling that particular call site or the method declaration must appear in the #implementation before the call site.