how to use a variable in another part of the code? - cocoa-touch

`- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSInteger *pushUpCount;
}
`- (IBAction)imPressed:(id)sender {
NSInteger pushUpCount = pushUpCount + 1;
NSString *strPushUp = [NSString stringWithFormat:#"%d", pushUpCount];
NSLog(strPushUp);
}
No my problem is that it says that the pushUpCount is not declared. So I was wondering how could I make this "public", so that all of the of the functions or IBActions can use this variable. I know what the problem is I don't know how to fix it.
CODE EXPLANATION
All I'm doing here is setting the variable to 0. Before the user does anything. Then each time the button is pressed it will add 1 to the existing number. then I will change the text of a NSTextField to the number but I know how to do that.(or I think I do at least).
So my basic question is..... How can I reuse a variable in another function or IBAction
Thanks in advance.

Make this variable a member of your class. I.e. declare it inside #interface section and assign it 0 inside viewDidLoad just like this: pushUpCount = 0;
Don't use it as a pointer (i'm pretty sure it's not what you need). Declare it NSInteger pushUpCount; instead of NSInteger *pushUpCount;
Inside imPressed just increment it pushUpCount++;
In order to make sure you understand everything i'll explain it very simple:
Your #interface section in YourViewController.h file should contain declaration of the variable:
#interface YourViewController : UIViewController
{
NSInteger pushUpCount;
}
#end
Now your code looks like:
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
pushUpCount = 0;
}
- (IBAction)imPressed:(id)sender {
pushUpCount++;
NSString *strPushUp = [NSString stringWithFormat:#"%d", pushUpCount];
NSLog(strPushUp);
}

Related

How to get Class Objects to automatically display behaviour

I'm having trouble understanding a finer point of Writing and calling Classes. It's probably
easlier to grasp in Swift but it bothers me to start that study without
getting it right in obj_c first. Currently I do everything in the
ViewControllers with iVars and Globals. With two apps 18 months in the App
store its overdue to put them right.
I've formed a notion that properties are the Object's State, and any methods
within determine the Objects Behaviour but so far no-one is able to tell me.
here be a typical Class header:
#interface Math : NSObject
#property (nonatomic, assign) int a;
#property (nonatomic, assign) int b;
#property (nonatomic, assign) int c;
-(int)mathemagic:(int)a adding:(int)b;
#end
and the corresponding Class implementation:
#implementation Math
#synthesize a = _a;
#synthesize b = _b;
#synthesize c = _c;
- (instancetype)init {
self = [super init];
if (self) {
_a = 0;
_b = 0;
_c = 0;
}
return self;
}
-(int)mathemagic:(int)a adding:(int)b {
_c = (a + b);
return _c;
}
#end
and finally in the appropriate places in my ViewController
#import "Math"
- (void)viewDidLoad {
[super viewDidLoad];
Math *theMath = [Math alloc]; // makes no difference if I init[]
theMath.a = 10;
theMath.b = 20;
NSLog (#" answer is %i",theMath.c);
// but still outputs to:
// answer is 0
}
Now I know can make an iVar and do it this way,
int d = [self.theMath mathemagic:theMath.a adding:theMath.b];
NSLog (#" sum: %i",d);
But i shouldn't have to. Stanford CS193P seems to always make the Class a property of the ViewController, but then everything is again expressed as self.theMath.whatever and the Data Model is no longer encapsulated away from the VC ? Maybe Stanford leaves advanced distractions to Java graduates till later.
Well for this person who's read David Flanagan's "Java in A Nutshell" ,
and Niemeyer-Knudsen's "Learning Java", It's later Now.
I shouldn't have to touch theMath.c, just by assigning values to [ theMath.a ] and [ theMath.b ] should be enough.
Where am I wrong?
I think that is because you are setting a and b = 0 in alloc init . and you are not calling [self mathemagic:a adding:b] anywhere.
I think im Math.m you should change -(instancetype)init to
- (instancetype)initWith:(int)a andb:(int)b {
self = [super init];
if (self) {
_c = [self mathemagic:a adding:b];
}
return self;
}
and in viewDidLoad use
Math *theMath = [[Math alloc]initWith:10 andb:20];
Hope this helps :)
I think you have a misconception of how Objective-C classes work.
First of all, it takes two steps to create an object in Objective-C. You must both:
Dynamically allocate memory for the new object
Initialize the newly allocated memory to appropriate values
So your Math instance initialization should look like this:
Math *theMath = [[Math alloc] init];
Just calling alloc zeroes out all instance variables of the object. Although in your case it makes no difference using [Math alloc] or [[Math alloc] init], it's not good programming style.
Second, if by "automatically display behaviour" you mean logging the result of mathemagic:adding: method, then you should pass it as an argument to NSLog function instead of theMath.c
NSLog(#" should show the sum being %i", [theMath mathemagic:theMath.a adding:theMath.b]);

One NSDictionary visible everywhere in application

Now I am developing an iOS application which works like this:
User scans QR code,
App searches for a specific key - > value,
it gives out a value to the user.
Currently I have two ViewControllers - the main and "value" ViewController, which is inherited from main. The problem is that if I create NSDictionary in main VC it is not visible in "value" VC. Main VC gives only the string (QR code, the key) through the segue. So, the value VC has to search for key and display the value.
What I ask is some kind of global variable or one DataSource visible across the whole app. Of course, I can implement NSDictionary initialisation inside value ViewDidLoad method and it will work, but this is not the point. New modules are to be added there and the variable has to be global. I googled a lot and got the idea that singleton pattern can be helpful here. I tried to implement it, but no idea how to do. Do I need it, or it is too complex for this kind of DataSource?
Thank you!
The basic idea is, you will still need to #include the header file of the place where this dictionary will be. The solution that Naveen proposes means that you will be including the header for the app delegate wherever you want to access it. Whether to use the app delegate for this purpose or not is kinda grayish. Some people often do this, some say its a bad use of it.
The singleton approach means that you will create a class, that will always contain the same information since the init method will return object that was previously created.
For the singleton aproach, imagine I have a database manager class. So in the header of this class (the DatabaseManagerSingleton.h) ill have this:
#interface DatabaseManager : NSObject
+ (DatabaseManager*)sharedInstance;
// Your dictionary
#property (nonatomic,strong) NSMutableDictionary* someDictionary;
The implementation will look like this: (check how "sharedInstance" initializes the object)
#implementation DatabaseManager
#pragma mark - Singleton Methods
+ (DatabaseManager*)sharedInstance {
static DatabaseManager *_sharedInstance;
if(!_sharedInstance) {
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[super allocWithZone:nil] init];
});
}
return _sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)init
{
self = [super init];
if (self != nil)
{
// Custom initialization
_someDictionary = [[NSMutableDictionary alloc] init];
}
return self;
}
Now, a VERY important thing is that, any place you want to use this object should first include the header:
EDIT: To use it in your code:
1) add the header
#import "DatabaseManager.h"
2) initialize the object
DatabaseManager *databaseManager = [DatabaseManager sharedInstance];
3) do whatever you need
// Initialize the dictionary
databaseManager.someDictionary = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"OBJECT",#"someKey", nil]; // In this case the object is just a NSString.
// Access
[databaseManager.someDictionary objectForKey:#"someKey"];
Put as a property on Appdelegate
#property (nonatomic,strong) NSDictionary * sharedData;
Access anywhere like
NSDictionary *sharedData= ((APPDelegate *) [UIApplication sharedApplication].delegate).sharedData;

Allocating and Initializing in implementation .m file in Objective-C xcode

I'm trying to initialize an object under the implementation section of my program since I'm planning to use the same object for multiple methods. I'm getting an error by trying to do this and I was just wondering why. Here are some examples below:
#implementation Fraction {
NSString *test = [[NSString alloc] init];
}
OR
#implementation Fraction {
int x = 0;
}
Although if you don't initialize the variables, they work fine without any errors or warnings. I'm sure this is how the code was designed, but I was just curious as to why. Thanks in advance for your answers!
The curly brace section of #implementation is only for declaring instance variables. You can't initialize them or put any other code there.
The proper place to initialize the instance variables is in an init method:
#implementaiton Fraction {
NSString *test;
int x;
}
- (id)init {
if ((self = [super init])) {
test = #"";
x = 0;
}
return self;
}
By surrounding #implementation in braces, you're declaring iVars, not declaring constants. And even if you weren't trying to declare a constant, you need to move your initialization into an -init flavored method if you wish the variable to hold an "initial value". If you were trying to declare a constant, it needs to be done outside of an #implementation block.
In #implementation section you cannot initialize any of your variables, only declare them. For other things use - (id) init method, since it is logically called after allocation, like this: [[CustomObjectClass alloc] init]; In addition, to declare private variables, it is suggested to use class extensions in your .m file like this: #interface CustomClassName()

Property not set in drawRect method - iOS

I have been seeing some strange behavior when I try to access a class variable or a property in my drawRect method..
In my .h file I have the following
#interface DartBoard : UIView
{
Board * board;
int index;
}
#property (readwrite, assign, nonatomic) NSNumber * selectedIndex;
#end
In my .m file I have the following
#implementation DartBoard
#synthesize selectedIndex;
-(id)init
{
self.selectedIndex = [NSNumber numberWithInt:5];
index = 123;
return self;
}
- (void)drawRect:(CGRect)rect {
NSLog(#"selectedIndex: %d",[self.selectedIndex intValue]);
NSLog(#"index: %d",index);
}
#end
the output is
2012-06-12 19:48:42.579 App [3690:707] selectedIndex: 0
2012-06-12 19:48:42.580 App [3690:707] index: 0
I have been trying to find a solution but have had no luck..
I found a similar question but there was no real answer to the issue
See: UIView drawRect; class variables out of scope
I have a feeling drawRect is different that normal methods and is not getting the scope of the class correctly but how do I fix it?
Cheers
Damien
I have a feeling drawRect is different that normal methods and is not getting the scope of the class correctly
No, there is nothing special about -drawRect:.
There are two possibilities:
1. Your -init method is not being called.
You didn't say how this view gets created -- if you are manually calling [[DartBoard alloc] init], or if it is getting unarchived from a nib file.
If it's coming from a nib, UIView's unarchiving doesn't know that your init method should be called. It will call the designated initializer instead, which is -initWithFrame:.
So, you should implement that method instead, and make sure to call super!
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.selectedIndex = [NSNumber numberWithInt:5];
index = 123;
}
return self;
}
2. There might be two instances of your view: one that you are manually initing, and another one that comes from somewhere else, probably a nib. The second instance is the one that is being drawn. Since its variables and properties are never set, they show up as zero (the default value).
You could add this line to both your -init and -drawRect: methods, to see what the value of self is. (Or, check it using the debugger.)
NSLog(#"self is %p", self);

Add Objects to NSMutableArray in a Loop

I have problems getting NSMutableArray to work. I simplified the code for illustrating my problem. I have a class, which I use as a Data container.
#interface Question : NSObject {
int questionID;
NSString* text;
}
#property int questionID;
#property(nonatomic,retain)NSString* text;
#end
I am creating different instances of this container as follows:
.h
#import "Question.h"
#interface testViewController : UIViewController {
NSMutableArray* questions;
}
-(IBAction) start;
.m
....
- (void)viewDidLoad {
[super viewDidLoad];
questions=[[NSMutableArray alloc]init];
for (int i=0; i<5; i++) {
int questionID=i;
Question* question=[[Question alloc]init];
question.questionID=questionID;
question.text=[NSString stringWithFormat:#"text %d",i];
[questions addObject:question];
[question release];
}
}
..........
-(IBAction) start{
for (int i=0; i<[questions count]; i++) {
Question *theQuestion;
theQuestion=(Question*)[questions objectAtIndex:i];
NSLog(#"%d",theQuestion.questionID);
NSLog(#"%#",theQuestion.text);
NSLog(#"----------------------");
}
}
In ViewDidLoad instances of question are created in a loop and they are added to the NSMutableArray questions. After question has been added it is released. After populating the NSMutableArray a function start is executed by pressing a button on the UI. This function should print out the contents of the different questions.
The problem is when the function start is executed the NSMutableArray questions does not have the contents stored before and the program crashes on
NSLog(#"%d",theQuestion.questionID);
The interesting thing is that if I do not release the question on the function viewDidLoad, then everything works fine. However, I would miss releasing a variable I previously allocated and this should lead to a leak.
Does anybody has an idea how to do this properly?
It's quite possible that your issue lies elsewhere in your code, memory issues expose themselves in strange ways. Are you sure nothing else interacts with questions and its contents? I suggest you add a breakpoint to the code and explore its contents at the point of the crash.
When creating Question delete release and use this instead:
Question* question=[[[Question alloc]init] autorelease];
Also it might be a good idea to use autorelease pool here.