Global variables not initializing - objective-c

I have found several explanations how to fix this but none of them (that I found) are simple enough for me to understand. New to Objective-c.
I am looking to access an array in multiple classes in objective c. I am trying to create a global variable (I know inefficient) in a "Globals.h" class, Initialize them in another class, and access that information in yet another class.
Heres what I have.
In Globals.h
#import <UIKit/UIKit.h>
extern NSArray *globalRows;
#interface Globals : NSObject
#end
ViewController.m
#import "Globals.h"
-(void)initGlobal{
globalRows = [[NSArray alloc] initWithArray:rows];
}
The compiler does not want to Initialize the variable and I do not understand why.
EDIT:
The Globals class is only to hold the global variables there is no executable code in this class.
The reason I initialize in the ViewController is that is where the information needed is parsed and stored.
There is no error and the code will simply not compile.
EDIT2:
It seems I have found a very good explanation here!

NSObjects have a + (void)initialize method you can setup that get called during startup. You could also just call it from main as well.
Still, a better design pattern is to make a singleton to hold some global thing you want to access/use. Similarly putting the things inside your app delegate make them effectively global.

Related

Objective-C : Accessing fields in implementation

Is it possible to fields defined only in implementation but not in interface definition ?
#interface MyInterface .... #end --> dict not defined here!!!
#implementation MyInterface
...
NSDictionary *dict;
...
#end
In this case if somewhere I somehow accessed to this class, can I access to the dict or should I create a getter just like in Java ?
Edit after #Rob's answer
Thanks for the answer Rob, I wish I have the implementation of these interface and classes. Instead I am trying to bind two different libraries ( I know it is reallllly bad as architectural point of view but this is where I end up).
Basically, I am in react-native world. And we are using react-native-video as our player layer. But since AVPlayer does not support some subtitle types our head company sent us a library that needs a player instance and a view instance to draw subtitle on the view. I believe they will bind to events of the player and draw sub titles based on player states.
So react-native-video is in this github repo with the interface and implementation.
I find the UIView that includes the properties and casted it to the object itself RTCVideo in this case). But now I am stuck. I can go and change some stuff as per your suggestion in the "Development Pods" to be able to access but this is my last bullet :) I prefer to convince these two libraries in a friendly way :)
Yes, but the above syntax isn't what you want. The modern way to do this is with a class extension.
Your header file is the same:
#interface MyInterface
#end
But in your .m file, you create an extension by appending ():
#interface MyInterface ()
#property (nonatomic, readwrite) NSDictionary *dict;
#end
Now, inside your .m file, you can access self.dict normally, but outside of your .m file it won't appear available.
For full details, see Programming with Objective-C: Class Extensions Extend the Internal Implementation.
The syntax you've written actually creates a static (global) variable called dict that isn't tied to any instance.
It is possible to create raw instance variables using a {...} syntax, either on the extension or on the implementation, but this isn't used that often today, except for managing raw buffers that you don't want accessors for. The syntax is either:
#interface MyInterface () {
NSDictionary *_dict;
}
...
#end
or on the implementation:
#implementation MyInterface {
NSDictionary *_dict;
}
...
#end
But I recommend simple extensions with properties any time you can. And if you are considering creating an accessor for it, you definitely want to use #property and let the system do it for you.
If I understand your edits correctly, you're trying to read the internal ivars of an object that doesn't expose them with an accessor, correct? I believe specifically you want to access _player.
There's several common ways to do that. The key feature you want is Key-Value Coding.
The simplest approach for this problem is -valueForKey:
AVPlayer *player = [view valueForKey:#"player"];
The first thing -valueForKey: looks for is _<key>, and if it's just an object pointer (as in this case), it just returns it.
(This can be broken if a class return false for +accessInstanceVariablesDirectly, but the default is true, and it's unusual to override this.)
Another very common approach is to just declare any methods you know exist as a category. (This won't work for _player, since it's not a method, but in case you need similar things.) Imagine you wanted to call the "private" method -removePlayerTimeObserver. In your .m file, just say you know about it using a category:
#interface RCTVideo (PrivateMethods)
- (void)removePlayerTimeObserver;
#end
And since you know about it, you can call it:
[video removePlayerTimeObserver];
If you're wrong, and that method doesn't really exist, then the program will crash. In Objective-C, almost all rules are advisory. You can break them if you want to. ObjC programmers tend to be big rule-followers because otherwise the program crashes and ObjC has very clear rules that are pretty easy to follow. It's not because the system forces us to.

When do you create initialization methods in .m files using class extension?

I was going through one of Apple's tutorial (your second iOS app). Basically, you have a primary data class and a data controller class. Controller class manipulates the primary data objects by creating an array that holds them.
Suddenly this pops up:
"...But the “create the master collection” task is a task that only the data controller object needs to know about. Because this method does not need to be exposed to other objects, you do not need to declare it in the header file."
And turns out the initialization of the "master collection" appears in the .m file as a class extension instead of the header file. Why do we want to do this? What's wrong with declaring the method of initialization within the header file directly?
Header file of the data controller:
#import <Foundation/Foundation.h>
#class BirdSighting;
#interface BirdsSightingDataController : NSObject
#property (nonatomic, copy) NSMutableArray *masterBirdSightingList;
- (NSUInteger)countOfList;
- (BirdSighting *)objectInListAtIndex:(NSUInteger)theIndex;
- (void)addBirdSightingWithName:(NSString *)inputBirdName location:(NSString *)inputLocation;
#end
this is the corresponding .m file:
#import "BirdsSightingDataController.h"
#import "BirdSighting.h"
#interface BirdsSightingDataController ()
- (void)initializeDefaultDataList; //class extension
#end
#implementation BirdsSightingDataController
...
Putting methods in an interface inside of a .m file is the proper way of making methods hidden.
-
There's nothing really "wrong" with declaring this method in the header file. You can do this if you want.
However, it's better practice to hide methods in your implementation file by using private header extensions if there's no need to make the method public. This means that if no other class needs to call this method, or if no other programmer needs to call this method, then it's better practice to keep the method private, or hidden.
A case like this will help explain the situation:
First, putting methods in a hidden interface extension in your .m files is a conscious decision. As another developer, if I am looking at your code and see that you have consciously decided to put a method in a hidden interface () in your implementation file, I will know that this method is used only in this class... and that YOU have done this on purpose.
Furthermore, it is good practice because if you are developing an API which is going to be used by other people, or working on the same code base with other developers, it limits their ability to call specific methods outside of the class itself. That means, they can't accidentally call the method from another object.

Global Variables for Class Methods

Background
In Cocoa, Apple frequently makes use of the following paradigm:
[NSApplication sharedApplication]
[NSNotificationCenter defaultNotificationCenter]
[NSGraphicsContext currentContext]
[NSCalendar currentCalendar]
and so on.
They also will occasionally make use of a paradigm that I feel is far more legible when working with vast amounts of code.
NSApp //which maps to [NSApplication sharedApplication]
Goal
I'd love to be able to utilize this sort of global variable, both in my own classes, and in extensions to other classes.
MYClassInstance
NSDefaultNotificationCenter
NSCal /* or */ NSCurrentCalendar
and so on.
The "duh" Approach
#define. Simply #define NSCal [NSCalendar currentCalendar], but as we all know by now, macros are evil (or so they say), and it just doesn't seem like the right Cocoa way to go about this.
Apple's Approach
The only source I could find regarding NSApp was APPKIT_EXTERN id NSApp;, which is not exactly reusable code. Unless I'm mistaken, all this code does is define NSApp to be an id the world around. Unfortunately unhelpful.
Close, but not Quite
In my searches, I've managed to find several leads regarding "global constants", however things like this:
extern NSString * const StringConstant;
are unfortunately limited to compile-time constants, and cannot map to the necessary class method.
Bottom Line
I'd love to be able to roll my own NSApp-style global variables, which map to class methods like [NSNotificationCenter defaultNotificationCenter]. Is this possible? If so, how should I go about it?
Further Attempts
I'm trying to implement specifically the framework singletons in the following way:
MySingletons.h
//...
extern id NSNotifCenter;
//...
MySingletons.m
//...
+(void)initialize
{
NSNotifCenter = [NSNotificationCenter defaultCenter];
}
//...
MyAppDelegate.m
//...
#import "MySingletons.h"
//...
//in applicationDidFinishLaunching:
[MySingletons initialize];
NSLog(#"%#", NSNotifCenter);
//...
However, this results in a compile-time error where the _NSNotifCenter symbol cannot be found.
Goal!
I'm currently working on an Objective-C class to encapsulate some of the framework singletons I've referred to in this question. I'll add the GitHub information here when I get it up.
That's funny, I just made this suggestion on another question.
You just expose the variable that holds the singleton instance as a global itself. NSApp isn't actually mapping to a sharedApplication call. It's a regular old pointer; it was set up during the application launch process to point to the same instance that you would get back from that call.
Just like NSApp, you declare the variable for any file which imports the header:
extern MySingleton * MySingletonInstance;
in the header (you can use APPKIT_EXTERN if you like; the docs indicate that it just resolves to extern in ObjC anyways).
In the implementation file you define the variable. Usually the variable holding the shared instance is declared static to confine its linkage to that file. If you remove the static, the statement defines storage that is "redeclared" in the header.
Then, use it as you did before. The only caveat is that you still have to get your singleton setup method [MySingleton sharedInstance] called before the first time you use the global in order to make sure it's initialized. -applicationDidFinishLaunching: may be a good candidate for a place to do this.
As for creating pointers to framework singletons, you can just stash the result of [CocoaSingleton sharedInstance] in whatever variable you like: an ivar in a class that wants to use it, a local variable, or in a global variable that you initialize very early in your program via a function you write.
The thing is, that's not guaranteed not to cause problems. Except in the case of NSApp (or unless it's documented somewhere) there's really no guarantee that the object you get back from any given call to sharedInstance is going to remain alive, valid, or useful past the end of your call stack.
This may just be paranoia, but I'd suggest not doing this unless you can find a guarantee somewhere that the supposed singletons you're interested in always return the same instance. Otherwise, you might suddenly end up with a dangling global pointer.
Addressing your code, the declaration in your header doesn't create a variable. You still need a definition somewhere:
// MySingletons.h
// Dear compiler, There exists a variable, NSNotifCenter, whose
// storage is elsewhere. I want to use that variable in this file.
extern id NSNotifCenter;
// MySingletons.m
// Dear compiler, please create this variable, reserving memory
// as necessary.
id NSNotifCenter;
#implementation MySingletons
// Now use the variable.
// etc.
If you're creating a singleton, you might want to glance at Apple's singleton documentation.
The existing discussion here was so intriguing that I did a little research and discovered something I'd never realized before: I can #import a header file from my own project into the project's .pch file (the precompiled header). This header file becomes automatically visible to all the other class files in my project with no effort on my part.
So here's an example of what I'm now doing. In the .pch file, beneath the existing code:
#import "MyIncludes.h"
In MyIncludes.h are two kinds of thing, categories and externs (the latter in accordance with Josh's suggestion):
extern NSString* EnglishHiddenKey;
extern NSString* IndexOfCurrentTermKey;
#interface UIColor (mycats)
+ (UIColor*) myGolden;
+ (UIColor*) myPaler;
#end
In MyIncludes.m we provide definitions to satisfy all the declarations from the header file. The externs don't have to be defined from within any class:
#import "MyIncludes.h"
NSString* EnglishHiddenKey = #"englishHidden";
NSString* IndexOfCurrentTermKey = #"indexOfCurrentTerm";
#implementation UIColor (mycats)
+ (UIColor*) myGolden {
return [self colorWithRed:1.000 green:0.894 blue:0.541 alpha:.900];
}
+ (UIColor*) myPaler {
return [self colorWithRed:1.000 green:0.996 blue:0.901 alpha:1.000];
}
#end
Except for the part about using the pch file to get magical global visibility, this is not really any different from Josh's suggestion. I'm posting it as a separate answer (rather than a mere comment) because it's long and needs formatting, and the explicit code might help someone.
(Note that there is no memory management, because I'm using ARC. The externs leak, of course, but they are supposed to leak: they need to live as long as the app runs.)

Objective C shenanigans

In my quest to be the grandmaster of Objective C, I keep running into it's subtleties, which I want to share with ya'll and gain an understanding why
1) I have two init methods, the one that is inherited by NSObject for my Objective C class and one is a custom method that I create off my own, let's say
initCustomMethod:(int)par1 argument2:(int)par2;
My Aim is to call initCustomMethod through the provided init method, essentially
-(id)init{
return [self initCustomMethod:1 argument2:3];
}
Naturally, maintaining the order, I have init appearing before initCustomMethod in the .m file. Xcode warns me telling me that the initCustomMethod is not found, I go ahead and shuffle the order and have init appearing after initCustomMethod is declared and there is no such warning message anymore and everything is fine.
I concur that the order is important since it's essentially derived from C, however I am not sure of this. Because, i shuffled the order of some properties and their custom methods, with the properties #synthesize being declared after the custom setter method for a given property, but there was no such error replica.
Can anyone point out the malice here?
Thanks guys!!!
Very cool guys, thanks for helping me out with this. Also, since I have a custom init method, I am initializing the super in this method and using the original init method to call the custom init method.
Anything wrong with this?
Before you reference it anywhere, you should declare initCustomMethod:argument2 in your interface, which would usually be in your header file.
For example, you would usually have a .h file that looks like:
#interface MyClass
{
//instance variables
int anInstanceVariable;
}
// properties
#property (nonatomic, assign) int aProperty;
// methods
-(id)initCustomMethod:(int)par1 argument2:(int)par2;
#end
And if you did this, the order in which you define init and initCustomMethod:argument2: won't matter. This is because the declaration tells the compiler that you are going to define the method, and what it will look like, so it isn't confused when you use it later.
It's a bad idea in Objective-C to use a function or a method before it is either declared or defined. Putting initCustomMethod:argument2: before init means that the former is already defined in the latter. But if you'd just declare it in the header, it wouldn't matter which order they went in.
Add your custom method name in your header file - the compiler just goes through things in order. If you don't have a forward declaration, the compiler won't know what to do with that call. You're going to need to put it in the header if you want other parts of your program to be able to call it anyway.

Objective-C: what is private what is not?

Why are people using
#interface ViewController : UIViewController
{
#private
UIButton* button_;
}
#private declarations in public headers? Declaring a variable inside an implementation yields the same result, doesn't it? It feels strange to me, I thought a public header should only contain really public members. What to do with protected members?
#implementation ViewController
UIButton* button_;
#end
The only difference I know of is that this variable is only visible inside the current compilation unit (the .m file, right?)
Does the same hold true for methods? I could compile fine with proper method ordering or forward declarations. Why do people care to declare categories for private methods? For testing purposes only?
The variable declaration inside the #implementation block will create a global variable, and not an instance variable. Instance variables need to be defined as part of the #interface.
While you can create an additional #interface block, by means of a category or extension, but it can only contain method declarations, and not instance variables.
I would say that while it might "feel" wrong to you to put private instance variables in a supposedly public header, I wouldn't worry about it.
Take a look at pretty much any header file for a Cocoa class (except for the cluster classes), and you'll see that Apple declares their instance variables in their public header files.
Since Apple is OK with it, I don't think you have much to worry about. =)
FYI: All instance variables are protected by default.
Does the same hold true for methods?
No, methods are visible to any part of the program. If you know the selector you can callit.
I could compile fine with proper method ordering or forward declarations. Why do people care to declare categories for private methods? For testing purposes only?
Private categories are a form of forward declaration. You can think of them as if they were C prototypes.
Andrew
#private is referring only to the iVars.
By default you can access ivars of an instance like so:- id iShouldNotDoThis = foo->bar;
#private means you can't access the ivar like that and have to use the access methods.
id thisIsBetter = [foo bar];
Nothing to do with private categories or methods.