I'm trying to wrap head around Reactive Cocoa, everything works fine except RAC(self.windButton.enabled) sections (at the bottom), reduce blocks never gets called. Would be glad if someone could point me my errors. The code is self-explaining, basically app looks like this:
Here is implementation
#import "ViewController.h"
#interface ViewController ()
#property (strong, nonatomic) NSNumber *winding;
#property (strong, nonatomic) NSNumber *minWinding;
#property (strong, nonatomic) NSNumber *maxWinding;
#property (weak, nonatomic) IBOutlet UIButton *windButton;
#property (weak, nonatomic) IBOutlet UIButton *unwindButton;
#property (weak, nonatomic) IBOutlet UILabel *windingLabel;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.winding = #0;
self.minWinding = #0;
self.maxWinding = #15;
RACSignal *windingSignal = RACAble(self.winding);
RACSignal *maxWindingSignal = RACAble(self.maxWinding);
RACSignal *minWindingSignal = RACAble(self.minWinding);
RAC(self.windingLabel.text) = [windingSignal map:^id(NSNumber *winding) {
return winding.stringValue;
}];
[[self.windButton rac_signalForControlEvents:UIControlEventTouchUpInside]
subscribeNext:^(id sender) {
self.winding = #(self.winding.integerValue + 1);
}];
[[self.unwindButton rac_signalForControlEvents:UIControlEventTouchUpInside]
subscribeNext:^(id sender) {
self.winding = #(self.winding.integerValue - 1);
}];
RAC(self.windButton.enabled) = [RACSignal
combineLatest:#[windingSignal, maxWindingSignal]
reduce:^(NSNumber *winding, NSNumber *maxWinding) {
return #(winding.intValue < maxWinding.intValue);
}];
RAC(self.unwindButton.enabled) = [RACSignal
combineLatest:#[windingSignal, minWindingSignal]
reduce:^(NSNumber *winding, NSNumber *minWinding) {
return #(winding.intValue > minWinding.intValue);
}];
}
My problem is that buttons never get disabled.
I had to use RACAbleWithStart to pre-fill signal with initial values since combineLatest method waits until every provided signal has some value.
RACSignal *windingSignal = RACAbleWithStart(self.winding);
RACSignal *maxWindingSignal = RACAbleWithStart(self.maxWinding);
RACSignal *minWindingSignal = RACAbleWithStart(self.minWinding);
The RAC() macro takes two arguments at a minimum.
check out this question
Related
I am having problems unable to set values taken from UItextfields from a Viewcontroller to another class which does the calculations from those values.
#interface InitialViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *phValue;
#property (weak, nonatomic) IBOutlet UITextField *pco2Value;
#property (weak, nonatomic) IBOutlet UITextField *hco3Value;
#property (weak, nonatomic) IBOutlet UITextField *sodiumValue;
#property (weak, nonatomic) IBOutlet UITextField *chlorideValue;
#property (nonatomic,retain)NSDecimalNumber* ph;
#property (nonatomic,retain) NSDecimalNumber* pco2;
#property (nonatomic,retain)NSDecimalNumber* hco3;
#property (nonatomic,retain)NSDecimalNumber* sodium;
#property (nonatomic,retain)NSDecimalNumber* chloride;
- (IBAction)analyseValues:(UIButton *)sender;
#end
in the implementation
-(void)values{
[self setPh:[[NSDecimalNumber alloc] initWithFloat:phValue.text.floatValue ]];
[self setPco2:[[NSDecimalNumber alloc] initWithFloat:pco2Value.text.floatValue]];
[self setHco3:[[NSDecimalNumber alloc ] initWithFloat:hco3Value.text.floatValue]];
[self setSodium:[[NSDecimalNumber alloc] initWithFloat:sodiumValue.text.floatValue] ];
[self setChloride:[[NSDecimalNumber alloc] initWithFloat:chlorideValue.text.floatValue] ];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self values];}
Then I have another class which takes these values ,but on running the program it runs but does assign values taken from the initialViewController.
#import <Foundation/Foundation.h>
#import "InitialViewController.h"
#interface AcidBaseCalculations : NSObject
#property (nonatomic) float ph;
#property (nonatomic) float pco2;
#property (nonatomic) float chloride;
#property (nonatomic) float sodium;
#property (nonatomic) float hco3;
#implementation AcidBaseCalculations
#synthesize ph,pco2,chloride,hco3,sodium;
-(void)calculations{
InitialViewController *bvc = [[InitialViewController alloc] init];
ph = bvc.ph.floatValue ;
pco2 = bvc.pco2.floatValue;
// these values are not being set although the program runs successfully
hco3 = bvc.hco3.floatValue;
sodium = bvc.sodium.floatValue;
chloride = bvc.chloride.floatValue;
I want to use these new values here and perform some logical operations in this class.
You are creating a new InitialViewController with this line:
InitialViewController *bvc = [[InitialViewController alloc] init];
It is a diffrent instance than your other/original InitialViewController
You either have to make a property
#property(nonatomic,strong)InitialViewController myInitialVC;
And set this property when you are alloc/initing your AcidBaseCalculations.
Our you have to make property for all variables you would like to calculate and set them while alloc/initing to the
AcidBaseCalculations
What I want:
On the iPhone user enters few values and tap on save button.
App should store the values in an instance of VehicleClass and add it to an NSMutableArray.
Hope you can help.
ViewController.h
#import <UIKit/UIKit.h>
#import "VehicleClass.h"
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *producerTextField;
#property (weak, nonatomic) IBOutlet UITextField *modelTextField;
#property (weak, nonatomic) IBOutlet UITextField *pYearTextField;
#property (weak, nonatomic) IBOutlet UITextField *priceTextField;
#property (weak, nonatomic) NSMutableArray *carArray;
#property (weak, nonatomic) IBOutlet UILabel *statusLabel;
- (IBAction)addCar:(id)sender;
- (IBAction)showCars:(id)sender;
#end
ViewController.m
#synthesize producerTextField, modelTextField, pYearTextField, priceTextField, carArray;
- (void)viewDidLoad
{
[super viewDidLoad];
carArray = [NSMutableArray array];
}
- (IBAction)addCar:(id)sender
{
VehicleClass *newVehic = [[VehicleClass alloc]initWithProducer:producerTextField.text
andModel:modelTextField.text
andPYear:producerTextField.text
andPrice:priceTextField.text];
[carArray addObject:newVehic];
if (carArray != nil) {
statusLabel.text = #"Car saved to array.";
}
else {
statusLabel.text = #"Error, check your code.";
}
}
VehicleClass.h
#import <Foundation/Foundation.h>
#interface VehicleClass : NSObject
#property (weak, nonatomic) NSString *producer;
#property (weak, nonatomic) NSString *model;
#property (weak, nonatomic) NSString *pYear;
#property (weak, nonatomic) NSString *price;
-(id)initWithProducer:(NSString *)varProducer
andModel:(NSString *)varModel
andPYear:(NSString *)varPYear
andPrice:(NSString *)varPrice;
#end
VehicleClass.m
#import "VehicleClass.h"
#implementation VehicleClass
#synthesize model, price,pYear,producer;
-(id)initWithProducer:(NSString *)varProducer
andModel:(NSString *)varModel
andPYear:(NSString *)varPYear
andPrice:(NSString *)varPrice
{
self = [super init];
if (self != nil)
{
producer = varProducer;
model = varModel;
pYear = varPYear;
price = varPYear;
}
return self;
}
#end
Maybe the problem has something to do with my init method?
carArray is a weak property, it should be strong.
Also: you should use self.carArray and not carArray. When you use carArray, you are using the underlying iVar and not the actual property. It will cause confusion later.
Your properties should be, instead of property (weak, nonatomic), property (nonatomic, retain).
In your init method, put:
-(id)initWithProducer:(NSString *)varProducer
andModel:(NSString *)varModel
andPYear:(NSString *)varPYear
andPrice:(NSString *)varPrice
{
self = [super init];
if (self != nil)
{
self.producer = varProducer;
self.model = varModel;
self.pYear = varPYear;
self.price = varPYear;
}
return self;
}
Then, to check if your carArray has objects, instead of using if (carArray != nil), use if ([carArray count] > 0), because you already init it.
Your carArray is weak property. carArray should be strong.
I have made a very simple NSObject:
GameSetUpData.h
#interface GameSetUpData : NSObject
#property (readwrite, nonatomic) NSUInteger numberOfPlayers;
#property (strong, nonatomic) NSMutableArray *playerNames;
#property (strong, nonatomic) NSString *gameType;
#property (readwrite, nonatomic) NSUInteger numberOfMinutes;
#property (readwrite, nonatomic) NSUInteger numberOfTurns;
#property (readwrite, nonatomic) CGSize boardSize;
#end
GameSetUpData.m
#import "GameSetUpData.h"
#implementation GameSetUpData
#synthesize numberOfPlayers = _numberOfPlayers;
#synthesize playerNames = _playerNames;
#synthesize gameType = _gameType;
#synthesize numberOfMinutes = _numberOfMinutes;
#synthesize numberOfTurns = _numberOfTurns;
#synthesize boardSize = _boardSize;
#end
This class basically just holds data. I then try to use this object in my viewcontroller:
MainMenu.h
#import <UIKit/UIKit.h>
#class GameSetUpData;
#interface MainMenu : UIViewController
#property (strong, nonatomic) GameSetUpData *gameSetUp;
-(IBAction)tappedNewGame:(id)sender;
-(IBAction)tappedTwoPlayers:(id)sender;
...
MainMenu.m
#import "MainMenu.h"
#import "MJViewController.h"
#import "GameSetUpData.h"
#implementation MainMenu
#synthesize gameSetUp = _gameSetUp;
...
-(IBAction)tappedTwoPlayers:(id)sender {
_gameSetUp.numberOfPlayers = 2;
NSLog(#"number of Players: %d", _gameSetUp.numberOfPlayers);
}
Unfortunately, my NSLog says that numberOfPlayers is equal to 0. What is wrong with my GameSetUpData? I was told that in iOS5 we do not need to call alloc/init or make a dealloc method. Do I still need a -(void)init method in GameSetUpData. Thank you all for your time!
Edit: Please alloc/init your objects -- ARC ONLY deals with release/retain/autorelease. You still need to make an instance of an Object! I apologize for the mis-information. I will make sure to RTFM next time...
Of course you have to alloc/init your object. How should the compiler know when to do that? With ARC you just don't need to retain or release.
Add _gameSetUp = [[GameSetUpData alloc] init]; somewhere.
I want to call a function in a viewController from my appDelegate but with the following code, it doesn't get called. What am I doing wrong?
AppDelegate.h:
#import <UIKit/UIKit.h>
#import "DetailsToTransfer.h"
#class AccountDetailTransferViewController;
#interface AccountDetailTransferAppDelegate : NSObject <UIApplicationDelegate> {
DetailsToTransfer *objDetailsToTransfer;
}
#property (nonatomic, retain) DetailsToTransfer *objDetailsToTransfer;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet AccountDetailTransferViewController *viewController;
-(void)sendToTransferScreen:(NSArray *)detailsArray;
#end
AppDelegate.m:
....
-(void)sendToTransferScreen:(NSArray *)detailsArray {
[objDetailsToTransfer setLabels:detailsArray];
objDetailsToTransfer = [[DetailsToTransfer alloc]initWithNibName:#"DetailsToTransfer" bundle:nil];
[self.window addSubview:objDetailsToTransfer.view];
}
DetailsToTransfer.h:
#import <UIKit/UIKit.h>
#interface DetailsToTransfer : UIViewController {
NSArray *accountDetailsArray;
UILabel *nameLabel;
UILabel *accountLabel;
IBOutlet UIButton *btnTransfer;
IBOutlet UIButton *btnBack;
}
#property (nonatomic, retain) NSArray *accountDetailsArray;
#property (nonatomic, retain) IBOutlet UILabel *nameLabel;
#property (nonatomic, retain) IBOutlet UILabel *accountLabel;
-(IBAction)sendDetails;
-(IBAction)goBack;
-(void)setLabels:(NSArray *)array;
#end
DetailsToTransfer.m
....
-(void)setLabels:(NSArray *)array {
NSLog(#"Setting Labels");
self.nameLabel.text = [array objectAtIndex:0];
self.accountLabel.text = [array objectAtIndex:1];
}
....
I would like to add that all the properties have been synthesized and that I'm calling the method in the appDelegate properly (i checked using NSLogs)
In AppDelegate.m:
Looks as if you are calling a method on your object before the object has been created. Until you have alloc / init your object, there will be no labels to set text.
Try changing your method to this:
-(void)sendToTransferScreen:(NSArray *)detailsArray {
if (!objDetailsToTransfer) {
objDetailsToTransfer = [[DetailsToTransfer alloc]initWithNibName:#"DetailsToTransfer" bundle:nil];
[objDetailsToTransfer setLabels:detailsArray];
[self.window addSubview:objDetailsToTransfer.view];
}
}
The problem might be that you are trying to set the values on a object that hasn't been created yet. I also provided an if statement to prevent the object from being created multiple times.
I have a problem that I have been searching for a solution for but can't seem to find one that works. UserInput.xib , Calculations.h & .m ,DataOutput.xib ... there is no .xib for that calculations.
UserInput.h
DataOutput *dataOutput;
UITextField *tf1;
UITextField *tf2;
UITextField *tf3;
#property (nonatomic, retain) DataOutput *dataOutput;
#property (nonatomic, retain) IBOutlet UITextField *tf1;
#property (nonatomic, retain) IBOutlet UITextField *tf2;
#property (nonatomic, retain) IBOutlet UITextField *tf3;
UserInput.m
#synthesize dataOutput;
#synthesize tf1;
#synthesize tf2;
#synthesize tf3;
- (IBAction)calculate:(id)sender {
DataOutput *dataOut = [[DataOutput alloc] initWithNibName:#"DataOutput" bundle:nil];
Calculations *calc = [[Calculations alloc] init];
dataOut.dataCalc = calc;
dataOut.dataCalc.tf1 = tf1.text;
dataOut.dataCalc.tf2 = tf2.text;
dataOut.dataCalc.tf3 = tf3.text;
dataOut.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:dataOut animated:YES];
[dataOut release];
DataOutput.h
Calculations *dataCalc;
UILabel *results1;
UILabel *results2;
UILabel *results3;
#property (nonatomic, retain) Calculations *dataCalc;
#property (nonatomic, retain) IBOutlet UILabel *results1;
#property (nonatomic, retain) IBOutlet UILabel *results2;
#property (nonatomic, retain) IBOutlet UILabel *results3;
DataOutput.m
#synthesize results1;
#synthesize results2;
#synthesize results3;
- (void)viewDidLoad {
self.results1.text = dataCalc.tf1;
self.results2.text = dataCalc.tf2;
self.results3.text = dataCalc.tf3;
Calculations.h
NSString *tf1;
NSString *tf2;
NSString *tf3;
NSString *results1;
NSString *results2;
NSString *results3;
float *tempResults1;
float *tempResults2;
float *tempResults3;
#property (nonatomic, retain) NSString *tf1;
#property (nonatomic, retain) NSString *tf2;
#property (nonatomic, retain) NSString *tf3;
#property (nonatomic, retain) NSString *results1;
#property (nonatomic, retain) NSString *results2;
#property (nonatomic, retain) NSString *results3;
- (float)getResults1;
- (float)getResults2;
Calculations.m
#synthesize tf1;
#synthesize tf2;
#synthesize tf3;
#synthesize results1;
#synthesize results2;
#synthesize results3;
- (float) getResults1 {
float temp1 = [tf1 floatValue];
float temp2 = [tf2 floatValue];
if (temp1 <= 1 && temp2 >= 3) {
if (temp2 ==10) {tempResults1 = 50;}
else if (temp2 == 11) {tempResults1 = 52;}
etc etc etc ok here is my problem..with the way I have things setup I can carry data from the userInput, threw Calculations and display them in a label on the DataOutput. BUT, when
using the floats in those if statements on calculations.m that I declared in calculations.h... I can't carry the floats (the actual data calculations) over to the DataOutput screen. on DataOutput when I try to set it a float from calculations it doesn't recognize it, it will recognize the NSString but not the float. I have tried converting float tempResults1 to NSString results1 and i keep getting errors. I have tried several different ways to go about doing this from different questions and answers on here but can't figure out why it wont work. can anyone help me with this?
What I want to do is to be able to display results from the calculations on the dataoutput screen.
I know it has to be something simple, maybe I'm doing something wrong or overlooking looking something I didn't do ... I don't know, I could use a little guidance though I know that much.
if (temp1 <= 1 && temp2 >= 3) // this is ok
{
if (temp2 ==10) { // exact floating point comparisons are dangerous,
// and should be avoided. you must rewrite this.
// turn up your compiler warnings
tempResults1 = 50; // this is not what you think it is.
// turn up your compiler warnings. you
// are assigning the address for the
// pointer's value. this will lead to a
// crash after you use it. what exactly
// are you trying to accomplish with this
// statement? this must be rewritten.
}
else if (temp2 == 11) {tempResults1 = 52;} // as above