I asked a question:link
After discussing this issue, I will rewrite the original program, become Singleton methods.
I'll call timer which way to write in MySingleton,then TimerViewController inside to call MySingleton's method :
MySingleton.h
#interface MySingleton : NSObject
{
int remainder;
NSTimer *timer;
NSTimeInterval countDownInterval;
int hours;
int mins;
int secs;
}
#property(nonatomic, retain)NSString *displayText;
#property int afterRemainder;
+(MySingleton*) getInstance;
-(void)doSomethingWithString:(int*)parameter;
#end
MySingleton.m
-(void)doSomethingWithString:(int*)parameter {
remainder = *parameter;
_afterRemainder = *parameter - remainder % 60 ;
timer=[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(updateCountDown)userInfo:nil repeats:YES];
}
-(void)updateCountDown{
_afterRemainder --;
hours = (int)(_afterRemainder/(60*60));
mins = (int)(((int)_afterRemainder/60)-(hours * 60));
secs = (int)(((int)_afterRemainder - (60 * mins) - (60 * hours *60)));
displayText = [[NSString alloc]initWithFormat:#"%02u : %02u : %02u",hours,mins,secs];
}
TimerViewController.h
#interface TimerViewController : UIViewController
#property (retain, nonatomic) IBOutlet UIDatePicker *CountDown;
#property (retain, nonatomic) IBOutlet UILabel *LabTimer;
#property (retain, nonatomic) IBOutlet UIButton *BtnStart;
- (IBAction)StartCmd:(id)sender;
#end
TimerViewController.m
Here to call timer,UILabel is placed TimerViewController.m
- (IBAction)StartCmd:(id)sender {
MySingleton* singleton = [MySingleton getInstance];
nowInterval=(NSTimeInterval)CountDown.countDownDuration;
nowTimer = nowInterval;
[singleton doSomethingWithString:&(nowTimer)];
}
TimerViewContorller have one Label call LabTimer, MySingleton have a NSString call display text I want to call LabTimer in MySingleton,and displays displaytext in LabTimer
I don't know how to do it?
don't understand u're question. But show u how singleton may work.
so:
u have some Singleton class: MySingleton.
h.file
#interface MySingleton : NSObject {
}
+ (id)sharedManager;
- (void)SomeMethod:(int)someParameter;
#end
m file
#implementation MySingleton
+ (id)sharedManager {
static MySingleton *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
#pragma mark - Some public Method
- (void)SomeMethod:(int)someParameter
{
// code here
[self somePrivateMethod];
}
#pragma mark - Some private Method
- (void)somePrivateMethod {
// code here
}
And u can use this class inside u're MainClassController:
like this:
// some code before
/* call singleton `Some Method` */
[[MySingleton sharedManager] SomeMethod:'int value'];
// code after
Maybe its helps u . Good luck)
You need to set the text of the UILabel when the timer fires. Move the assignment statement that assigns displayText into the timer's action method (updateCountDown).
By the way, I don't understand UILabel.text = ... I assume that this is a syntax error in your code.
When you do an assignment like this:
myLabel.text = displayText;
what happens is that the right-hand side expression (a single variable in this case) is evaluated and its value at the time the statement is executed is assigned to the text property of the UILabel (and the user sees it). If you change the value of displayText later, that will make no difference to what the user sees - the assignment to the text property has to be executed again. I hope this is clear.
To solve your problem:
Add a weak reference to TimeViewController to MySingleton:
#property (weak) TimeViewController* myViewController;
Before calling doSomethingWithString, assign self to singleton
MySingleton* singleton = [MySingleton getInstance];
nowInterval=(NSTimeInterval)CountDown.countDownDuration; nowTimer =
nowInterval; singleton.myViewController = self; [singleton
doSomethingWithString:&(nowTimer)];
Whenever the timer fires, call a method of TimeViewController
... displayText = [[NSString alloc]initWithFormat:#"%02u : %02u :
%02u",hours,mins,secs]; [self.myViewController
updateDisplay:displayText];
Related
Hy again, I am still new to objective c and Xcode. I am building a small app and need to use a variable in a Method. I don't know where to put it so I can use it in the Method.
I have a button which starts the whole process but the Method of this button needs a variable which only should be created once (because its a random number) and be saved so the "Button Method" can use it to compare it. Where do I place it so my variable stays the same while my Method can use it?
Thx
- (IBAction)guessButton:(id)sender {
NSLog(#"Answer = %i", answer);
NSLog(#"Button Pressed");
float guess = [[self.guessTextField text] floatValue];
NSLog(#"Guess = %f", guess);
}
Create in .h file like this....
#import <UIKit/UIKit.h>
#interface GoogleMapsViewController : UIViewController
#property int answer;//If it's int. Here mention your variable type(If it string #Property NSString * answer;)
#end
And call with self.answer
- (IBAction)guessButton:(id)sender {
NSLog(#"Answer = %i", self.answer);
NSLog(#"Button Pressed");
float guess = [[self.guessTextField text] floatValue];
NSLog(#"Guess = %f", guess);
}
It is recommended to store private variables in implementation class. We can define variable in .m file like this
#interface ViewController (){
NSString *stringTodefineAge;
}
#property (readonly, strong, nonatomic) ModelController *modelController;
#end
#implementation RootViewController
....
I have been trying to solve this for many hours. None of the posts I have found anywhere has provided a solution. The problem is the textField is in a subview and I cannot figure out how to make it respond to the Return button to hide the keyboard.
Here is my view controller;
#import <UIKit/UIKit.h>
#import "Combatant.h"
#interface ViewController : UIViewController <CombatantDelegate>
- (IBAction) addView;
- (IBAction) roll;
#end
#import "ViewController.h"
static int startY = 60;
#interface ViewController ()
{
NSMutableArray * customViews;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
customViews = [[NSMutableArray alloc] init];
}
- (IBAction) addView
{
Combatant * thing = [[NSBundle mainBundle] loadNibNamed:#"Combatant" owner:nil options:nil][0];
[self.view addSubview: thing];
thing.center = CGPointMake(self.view.center.x, startY + customViews.count * thing.bounds.size.height);
thing.combatDelegate = self;
[customViews addObject:thing];
}
- (IBAction) roll
{
for (Combatant * cust in customViews)
{
[cust rollWasTapped];
}
}
#end
Here is my custom Class;
#import <UIKit/UIKit.h>
#class Combatant;
#protocol CombatantDelegate <NSObject>
#end
#interface Combatant : UIView <UITextFieldDelegate>
{
IBOutlet UITextField * name;
IBOutlet UITextField * base;
IBOutlet UITextField * die;
IBOutlet UITextField * mod;
IBOutlet UILabel * total;
NSString *value;
int dRoll;
int cBase;
int cMod;
}
#property (nonatomic, strong, readwrite) NSString *value;
#property (nonatomic, strong) IBOutlet UITextField * name;
#property (nonatomic, strong) IBOutlet UITextField * base;
#property (nonatomic, strong) IBOutlet UITextField * die;
#property (nonatomic, strong) IBOutlet UITextField * mod;
#property (nonatomic) IBOutlet UILabel * total;
-(void) rollWasTapped;
-(BOOL) textFieldShouldReturn:(UITextField *)textField;
#property (nonatomic, weak) id<CombatantDelegate> combatDelegate;
-(int) dieRoll;
-(int) convertBase;
-(int) convertMod;
#end
#import "Combatant.h"
#implementation Combatant
#synthesize value;
#synthesize name;
#synthesize base;
#synthesize die;
#synthesize mod;
#synthesize total;
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
}
return self;
}
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[name resignFirstResponder];
return YES;
}
- (void) rollWasTapped;
{
int tot;
tot = [self convertBase] + [self dieRoll] + [self convertMod];
total.text = [NSString stringWithFormat:#"%i", tot];
NSLog(#" totaling %i ", tot);
}
-(int) dieRoll
{
int val = [die.text intValue];
if (val <7 && val >0)
{
NSLog(#" %i die", val);
} else {
NSLog(#" there are no dice");
val = 0; }
int d = 0;
for (int i = 0; i < val; i++) {
d = d + arc4random()%6 + 1;
}
dRoll = d;
NSLog(#"%i die roll result = %i ", val, dRoll);
return dRoll;
}
-(int) convertBase
{
cBase = [base.text intValue];
NSLog(#"base = %i", cBase);
if (cBase > -1 && cBase < 20)
{
return cBase;
}
return 0;
}
-(int) convertMod
{
cMod = [mod.text intValue];
NSLog(#"mod = %i", cMod);
if (cMod > -20 && cMod < 20)
{
return cMod;
}
return 0;
}
- (void) dealloc
{
self.combatDelegate = nil;
}
#end
The code works perfect in every aspect except the keyboard hiding.
In the most basic sense, you want the currently active text field to resignFirstResponder. Your problem seems to be how to access that text field.
edit: the below paragraphs jump topics quickly, as I'm detailing a few possible solutions instead of 1.
Goal: Accessing the Text field.
Solutions:
1) Create a property that exposes the text field on the custom class.
2) Create a function that calls the text field on the custom class.
You have 4 properties exposing the text fields, assuming there are 4 text fields on each view?
In that case, go with creating a function, and in that function, on the view, make sure it calls self.textField1 resign... blah, then self.textField2, just make sure it hits all of them.
Currently you call name resignFirstResponder in the callback. But first let's backtrace a little bit. All textFields call textFieldShouldReturn on their delegate. So make sure all 4 of your text fields have the view as the delegate. Either in interface builder or code, self.name.delegate (or self.name.textFieldDelegate, I forgot exactly) = self; for each one.
Also, remember to call "self.", "name" is something else. Actually self. accesses the property accessor. But the invisible variable it creates is called _name (same thing with an underscore at the beginning, this works for all properties).
Now that we know all your fields are being called correctly, let's get back to the delegate. If you really do want the "currently active, returning" text field to resign its responder, the delegate passes in its object view the textField, so just remember to call resignFirst... on the currently returning field.
[textField resignFirstResponder]
Of course, that belongs in the delegate callback method, since textField does not exist otherwise, lest you access it by its name (self.name, or the others).
Last but not least, put a button behind everything, but large enough to cover the screen, make it call a function. In that function, you can "splay" the call to every text field. Basically, make that function call the "hideTheKeyboard" or whatever you named it (the function that calls resignFirst... on all the fields within the custom view) on every custom view.
It should look like your function with for( view in customViews) but instead of calling roll, it calls your custom function.
Within that function, just because it is a possible solution, you can also do something like
- (IBAction) roll
{
for (Combatant * cust in customViews)
{
[cust.name resignFirstResponder];
[cust.die resignFirstResponder];
// and on for the other 2
}
}
But, as you can tell, the reason you might want that encapsulated into a function that you call is simply for less lines of code/simplicity. It is more important that you understand how and why you can do it either way than finding a solution that works. There are 3 solutions I've listed above (use a property, use a function to access the textField, or use the delegate).
The simplest is the delegate, the most compact is the function, and the most widespread is the property. (There are also limitations to each one). I wanted to give a thorough understanding so you can see them.
Put it in the textFieldDidEndEditing: method
- (void)textFieldDidEndEditing:(UITextField *)textField {
{
[textField resignFirstResponder];
}
In viewDidLoad add this:
name.delegate = self;
Or you can do this in the storyboard in the Connections Inspector, by dragging delegate outlet to your view controller.
PS: In this case, textFieldShouldReturn method should be in the view controller too.
You are using delegate which describes that if it should return or not? and before even you are returning you are sending event to your text field keyboard to return or dismiss which is not possible. please try the code as per mentioned by #soulshined.
- (void)textFieldDidEndEditing:(UITextField *)textField {
{
[textField resignFirstResponder];
}
I am working on a project that contains a Singleton instance of a class called Survey. Within that singleton instance is a property called "itemArray," which is an NSMutableArray that contains any number of instances of an Item class.
My Items class contains several NSInteger properties, but for the purposes of the application, I need to initialize all NSIntegers with a value of -1 instead of the default 0.
Now, for my Survey class (the one with the Singleton instance), I use the following method in the implementation to change the default value of a property:
-(id)init {
if (self = [super init]) {
_thingy = -1;
}
return self;
}
This works, but for some reason, the same exact syntax (with different properties) doesn't work for instances of my Item instances. For what it's worth, the following codeblock is the creation of 2 instances of Item, and their insertion into itemArray. I also tried the Item *item1 = [[Item alloc]init; method to no avail.
Item *item1;
[[[Survey sharedInstance]itemArray]insertObject:item1 atIndex:0];
Item *item2;
[[[Survey sharedInstance]itemArray]insertObject:item2 atIndex:1];
}
I would appreciate any assistance.
!!!!!UPDATE!!!!!
I entered the following conditional:
if (![[Survey sharedInstance]itemArray]){
NSLog(#"Test");
}
And the "test" logged onto the console, so it looks like the itemArray isn't being initialized. I'm not sure how to actually initialize it, though. When I try the following:
[[Survey sharedInstance]addressArray] = [[NSMutableArray alloc]init];
I'm getting an error saying "Expression is not assignable."
Survey.h:
#import <Foundation/Foundation.h>
#interface Survey : NSObject
+(instancetype)sharedInstance;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *emailAddress;
#property (nonatomic, assign) NSInteger trigger1;
#property (nonatomic, assign) NSInteger trigger2;
#property (nonatomic, assign) NSInteger trigger3;
#property (nonatomic, assign) NSInteger activeItem;
#property (nonatomic, strong) NSMutableArray *itemArray;
#end
Survey.m
#import "Survey.h"
#implementation Survey
+ (instancetype)sharedInstance {
static Survey *_instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[Survey alloc] init];
});
return _instance;
}
-(id)init {
if (self = [super init]) {
_storage = -1;
}
return self;
}
#end
Instead of
[[Survey sharedInstance]addressArray] = [[NSMutableArray alloc]init];
you need to use
[Survey sharedInstance].addressArray = [[NSMutableArray alloc]init];
or
[[Survey sharedInstance] setAddressArray:[[NSMutableArray alloc]init]];
You were trying to assign a value to the return value of a getter method, which is not possible, so the compiler was saying "Expression not assignable." You need to use the setter method or dot notation instead.
I have class ABCD.m, as below
**ABCD.m**
#property (nonatomic, strong) UIButton *button;
#property (nonatomic, strong) NSString *string;
- (void) firstMethod;
- (void) setTheButtonWithBool:(BOOL)var1 withString:(NSString *)var2;
-(void) firstMethod {
// Alloc init button
self.button.enabled = NO;
}
- (void) setTheButtonWithBool:(BOOL)var1 withString:(NSString *)var2 {
self.button.enabled = var1;
self.string = var2;
}
There is another class Test.m(subclass of XCTestCase) to write the unit test cases for ABCD.m
**Test.m** //Sub-class of XCTestCase
//Extension
#interface ABCD.m ()
#property (nonatomic, strong) UIButton *button;
#property (nonatomic, strong) NSString *string;
- (void) firstMethod;
- (void) setTheButtonWithBool:(BOOL)var1 withString:(NSString *)var2;
#end
#interace Test : XCTestCase
- (void)testSomeMethod {
ABCD *abcd = [ABCD alloc] init];
BOOL *var1 = YES;
NSString *var2 = #"StackOverFlow";
[abcd firstMethod];
[abcd setTheButtonWithBool:var1 withString:var2];
nslog(#"Result1 :%hhd", self.abcd.button.isEnabled); -----
nslog(#"Result2: %#", self.abcd.string); -----
// Assert statement
}
OUTPUT:
Result 1: NO
Result 2: StackOverFlow
When i set the property 'string' it is getting set to 'StackOverFlow'. But for UIButton property 'button' it is not getting set to 'NO'.
Why cant I set 'enabled' property of UIButton where as i can set the NSString of ABCD.m from the Test.m class
The problem is simple. You never set the button property on your ABCD instance. There is no code that creates a UIButton and assigns it to the button property.
A call like self.button.enabled = NO is translated to [[self button] setEnabled:NO]. Since you haven't set button, the call to [self button] returns nil. So now you call setEnabled: on a nil object which is basically a no-op.
Add code to create a button and set the button property and the rest of the code will work properly.
I created a method to calculate a simple calculation.
I want the method to return an int and take 2 int parameters.
I created a class called calculation. I imported calculation into the viewController.m and created an action 2 textFields and a text Label. I am using this view for testing the method.
My method return 0 in the calculation. What am I doing wrong? It's so simple but I can't seem to figure out where I'm making my mistake. Here is the code.
Calculation.h
#import <Foundation/Foundation.h>
#interface Calculation : NSObject
#property (nonatomic) int odometerStart;
#property (nonatomic) int odometerEnd;
#property (nonatomic) int odometerTotal;
- (int)mileageStart:(int)start mileageEnd: (int)end;
#end
Calculation.m
#import "Calculation.h"
#implementation Calculation
#synthesize odometerEnd, odometerStart, odometerTotal;
- (int)mileageStart:(int)start mileageEnd:(int)end
{
odometerStart = start;
odometerEnd = end;
odometerTotal = end - start;
return odometerTotal;
}
#end
viewController.h
#import <UIKit/UIKit.h>
#interface MileageViewController : UIViewController
- (IBAction)calculateMileage:(id)sender;
#property (strong, nonatomic) IBOutlet UITextField *startLabel;
#property (strong, nonatomic) IBOutlet UITextField *endLabel;
#property (strong, nonatomic) IBOutlet UILabel *displayLabel;
#end
viewController.m
#import "MileageViewController.h"
#import "Calculation.h"
#implementation MileageViewController
#synthesize startLabel;
#synthesize endLabel;
#synthesize displayLabel;
- (void)viewDidUnload
{
[self setStartLabel:nil];
[self setEndLabel:nil];
[self setDisplayLabel:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (IBAction)calculateMileage:(id)sender {
Calculation *mileage = [[Calculation alloc] init];
int odomStart = [[startLabel text] intValue];
int odomEnd = [[endLabel text ] intValue];
[mileage mileageStart:odomStart mileageEnd:odomEnd];
mileage.odometerTotal = displayLabel.text.intValue;
NSLog(#"THe total is %d", mileage.odometerTotal);
My total keeps equaling 0. The calculation isn't being calculated.
Your statement is backwards. You're trying to set the value of odometerTotal to the value of your label, but you want it the other way around. It should be:
displayLabel.text = [NSString stringWithFormat:#"%d",mileage.odometerTotal];
However, mileage returns an int value, so you don't really need the odometerTotal property in your Calculation class . You could do it like this:
displayLabel.text = [NSString stringWithFormat:#"%d",[mileage mileageStart:odomStart mileageEnd:odomEnd]];
I saw the whole program, and the assignment you did seemed wrong,
the bold pointed was as below:
mileage.odometerTotal = displayLabel.text.intValue;
you want to use the calculate class to calculate the total value. while the order should be opposite.
How about this:
displayLabel.text.iniValue = mileage.odometerTotal;
then use the NSLog method to print your expected result.