The accessor way are different with static int and static NSArray - ios

Below this demo code, the logical of the process is not important.
#interface ViewController ()<UITableViewDataSource, UITableViewDelegate>
#end
static int channelIndex = 0;
static NSMutableArray *channelsDataArray = nil;
#implementation ViewController
- (void)getSomething {
// Append the desiredValuesDict dictionary to the following array.
if (!self.channelsDataArray) {
self.channelsDataArray = [[NSMutableArray alloc] initWithObjects: desiredValuesDict, nil];
} else {
[self.channelsDataArray addObject:desiredValuesDict];
NSLog(#"channelsDataArray : %#", self.channelsDataArray);
}
// This will print the result I expected.
NSLog(#"channelIndxBefore: %i", channelIndex);
++channelIndex;
NSLog(#"channelIndxAfter: %i", channelIndex);
}
#end
The questions I have is that if I call the channelIndex in this way "self.channeIndex++" it will come out a warning:
Format specifies type 'int' but the argument has type 'NSInteger *'
(aka 'long *')
If I call this way "channelIndex++", which will work properly.
Strangely, I have another static NSMutableArray channelsDataArray, if I just call
[self.channelsDataArray addObject:desiredValuesDict];
It will work properly add object into the var. But if I just use
[channelsDataArray addObject:desiredValuesDict];
It will not show any warning, but the channelsDataArray will be nil, and can't assign the desiredValuesDict into it.
Question: When should I add self prefix or not? Why they are all static variable but one have to add self, another don't?

[Originally a comment:]
The error suggests you have another #interface (in a .h file) and that you've declared an instance variable in that file with the same name as the global variable you have declared in the quoted file. You need to remove one of them, which depends on what you need.
HTH

Related

Objective C - Static class variable of type NSArray

I'm storing some default initializer values for my class as static class variables. Like this:
// List.h
static NSString *DEFAULT_LIST_NAME = #"Not Set";
static BOOL DEFAULT_RECURSION = NO;
I also need a static variable of type NSArray * set to an empty array. How can this be achieved? Currently I get the error:
Initializer element is not a compile-time constant
You are getting the compile time error "Initializer element is not a compile-time constant" because the static variable's value is actually written into your executable file at compile time. So you can only use the constant values (not alloc/init which are executed at runtime). You can use any of the below option
You can write static NSArray *arr = nil and use +initialize to create your array.
Another options are you can use __attribute__ ((constructor))
Yet another option is to switch the type of your source file from Objective-C to Objective-C++ (or rename it from .m to .mm, which has the same effect). In C++, such initializers don't need to be compile-time constant values, and the original code would work just fine
Also you can use solution given Pat_Morita
define a class method for this:
.m file
#implementation test
static NSArray *array;
+ (NSArray *)array {
if (!array) array = [[NSArray alloc] init];
return array;
}
#end

NULL Custom Class Objects when outside viewDidLoad?

u1Option is an Option (custom class) object which is
declared and called in my ViewController viewDidLoad as:
- (void)viewDidLoad {
[super viewDidLoad];
Option *u1Option = [[Option alloc]init];
[u1Option setName: #"test"];
NSLog(#"Test1 Result: %#", u1Option.name);
}
Option is a custom class inheriting from NSObject and has a property declared in Option.h:
#property NSString *name;
However, if try to use u1Option in a IBAction, nothing is passed and while I get the "test" string in the Test1 NSLOG, on the contrary I get NULL in the Test2 NSLOG.
- (IBAction)addFirstOption:(UIButton *)sender {
NSLog(#"Test2 Result: %#", u1Option.name);
}
The Option instance is destroyed as soon as viewDidLoad returns. You need to put it in a property or instance variable. If it's already a property or instance variable then you are re-defining it, so use:
u1Option = [[Option alloc] init];
And this issue can be avoided in future by using self.u1Option or _u1Option.

JSONModel: Filling an NSArray of generic type

I'm using JSONModel in my iOS app and i'm facing some warnings, let me explain myself a bit.
Let's say i have this JSONModel
CTVContact.h
#interface CTVContact : JSONModel
#property (nonatomic, strong) NSArray<Optional, CTVPhone> *phone;
#end
CTVContact.m
NSMutableArray *phones = [[NSMutableArray alloc] init];
for(NSString *p in personPhones) {
CTVPhone *phn = [[CTVPhone alloc] init];
phn.original = p;
[phones addObject:phn];
}
phone = [NSArray arrayWithArray:phones];
Basically it all works like a charm but i get a warning stating the following:
Incompatible pointer types assigning to 'NSArray<Optional,CTVEventParticipant> *' from 'NSArray *'
How can i go around that warning? I can't find the right way to assign all the array values to the phone Array without that warning.
Thanks a lot in advance!
NSArray<Optional, CTVPhone> *phone; defines a variable that takes an array which conforms to 2 protocols. If you try and set that a variable (phone) to an array that doesn't state that it conforms to those protocols then you will get a compile warning.
phone = [NSArray arrayWithArray:phones]; just creates a 'plain' array, with no special protocols implemented. So you get a warning.
Probably the correct thing to do is to remove the protocols from the #property definition. Unless you have an NSArray subclass which conforms to those protocols that you should actually be using...
Alternatively, and assuming that you don't try to call any methods that might be defined in those protocols:
phone = (NSArray <Optional, CTVPhone> *)[NSArray arrayWithArray:phones];
which adds a cast that basically means to the compiler: 'trust me, it's fine'...
It looks like it may be complaining on your last line, since you're passing in an NSMutableArray when NSArray's arrayWithArray method calls for an NSArray. You can get away with this by calling copy on the phones array, as such:
phone = [NSArray arrayWithArray:[phones copy]];

Establishing a global array of strings [duplicate]

This question already has answers here:
How do I declare an array as a constant in Objective-c?
(6 answers)
Closed 9 years ago.
In my app I refer to a number of the same string variables from lots of different view controllers and I have created a number of global NSStrings using this method:
OpeningController.h (before #interface)
extern NSString *stringName;
OpeningController.m (after the #interface { } #end)
NSString *stringName =#"On";
I can then refer to/alter stringName anywhere in my application.
I want to be able to do the same with an array of strings but when I try the following I get the error Initializer is not a compile-time constant.
How do I achieve what I am trying to achieve?
OpeningController.h
extern NSArray *arrayName;
OpeningController.m (after the #interface { } #end)
NSArray *arrayName = [NSArray arrayWithObjects:
#"String1",
#"String2",
#"String3",
#"String4",
nil];
Assuming openingController is a class name (hint: it should be OpeningController) then you can initialize the array within the class's +initialize method, which will be invoked as soon as the class is referenced at runtime:
OpeningController.m:
#import "OpeningController.h"
NSArray *arrayName = nil;
#implementation OpeningController
+ (void)initialize {
arrayName = [NSArray arrayWithObjects:
#"String1",
#"String2",
#"String3",
#"String4",
nil];
}
....
#end
EDIT: Note that this isn't a particularly good example as referencing the array without referencing OpeningController first will access the un-initialized array. A better approach is a singleton pattern:
OpeningController.h:
#interface OpeningController : UIViewController // Not sure of the subclass
+ (NSArray *)array;
...
#end
OpeningController.m:
#import "OpeningController.h"
#implementation OpeningController
+ (NSArray *)array {
static NSArray *array = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
array = [NSArray arrayWithObjects:
#"String1",
#"String2",
#"String3",
#"String4",
nil];
});
return array;
}
...
#end
Don't use shared global variables. They create very strong coupling between your different classes, and force all sorts of interdependencies. That leads very quickly to spaghetti-code.
Instead, create a data container singleton. That is a singleton object (do a google search on the singleton design pattern in Objective C, or even search here) that contain properties that you want to share.
Then any time you want to read or write a global variable, you use your singleton's accessor method to fetch the singleton and then invoke the desired property.
NSUserDefaults is an example of a singleton in Apple's frameworks. The code
[NSUserDefaults sharedUserDefaults] is a class method call that returns a pointer to the user defaults singleton.
Your code might look something like [MyDataSingleton sharedDataSingleton].
You mus init the array, otherwise it will not work.
You can create a instance of the class and get that instance everytime you want.
If you have questions please tell me :)

NSArray, trying to pass the index number of the object in the array to a function

I have spent many hours trying to find a solution, so if it IS here somewhere and I missed it I am sorry ...
In .h
#property (nonatomic, strong) NSArray *physicalMan;
-(int) getManeuverRating:(int *) value;
In .m
physicalMan = [[NSArray alloc] initWithObjects:#"Grip-Hold", #"Strike", #"Fall", #"Response", nil];
NSLog(#" The second element is: %#", [physicalMan objectAtIndex:1]);
NSLog (#" This is the index location of Grip-Hold: %i", [physicalMan indexOfObject:#"Grip-Hold"]);
[self getManeuverRating:[physicalMan indexOfObject:#"Grip-Hold"]];
}
-(int) getManeuverRating:(int *) value
{
int a = *value;
return a + 1;
}
The NSLogs work fine with the proper values, which is why I am so confused as to why the function will not work.
The compiler warning says "Incompatible integer to pointer conversion sending 'NSUInteger' (aka 'unsigned int') to parameter of type 'int *'"
I have tried removing the * and I have tried to find other data types, and converting data types, and I cannot get anything to work correctly. Please help or point me in the right direction ... what am I doing wrong? what am I missing?
The indexOfObject: method of NSArray returns an NSUInteger, not an int*. Passing an int to a method that takes int* is incorrect: the value at the corresponding memory location would not be valid.
You should change the getManeuverRating: method as follows:
-(int) getManeuverRating:(NSUInteger) value
{
return value + 1;
}
You are not pointing to an int... you should make this function
-(NSInteger)getManeuverRating:(NSInteger) value
{
NSinteger a = value;
return a + 1;
}
If that is giving you issues you should also try casting the integer in the initial function...
So instead of
[self getManeuverRating:[physicalMan indexOfObject:#"Grip-Hold"]];
Do
NSInteger index = (NSInteger) [physicalMan indexOfObject:#"Grip-Hold"];
[self getManeuverRating:index];
You should be using NSInteger instead of int simply because it is good to write in objective-c syntax. But it is just a wrapper. You could also make it take and return an NSUInteger and not cast it.
Another modernization thing you could do (and this is an aside) is declare your array like this...
NSArray * physicalMan = #[#"Grip-Hold", #"Strike", #"Fall", #"Response"];

Resources