I was wondering if it is feasible for me to connect this simple console program I have in objective-c into a very simple iPhone application.
Since I have no experience using Interface Builder, I'm not sure how long it would take for me to learn it.
Also, I believe my code would have to be adjusted to some iPhone APIs, rather than using the console for input and output.
Here is the program's main.m file, where all of its code is store:
//Simple program to convert Fahrenheit to Celsius and Celsius to Fahrenheit
#import <stdio.h>
#interface Converter: NSObject
{
//Instance variable which stores converting formula for objects
double formula;
}
//Declare instance methods for setting and getting instance variables
-(void) convert: (double) expression;
-(double) formula;
#end
#implementation Converter;
//Define instance method to set the argument (expression) equal to the instance variable
-(void) convert: (double) expression
{
formula = expression;
}
//Define instance method for returning instance variable, formula
-(double) formula
{
return formula;
}
#end
int main (int argc, char *argv[])
{
//Point two new objects, one for the Fahrenheit conversions and the other for the Celsius conversions, to the Converter class
Converter *fahrenheitConversion = [[Converter alloc] init];
Converter *celsiusConversion = [[Converter alloc] init];
//Declare two double variables holding the user-inputted data, and one integer variable for the if else statement
double fahrenheit, celsius;
int prompt;
NSLog(#"Please press 0 to convert Celsius to Fahrenheit, or 1 to convert Fahrenheit to Celsius\n ");
scanf("%d", &prompt);
if(prompt == 0) {
NSLog(#"Please enter a temperature in Celsius to be converted into Fahrenheit!:\n");
scanf("%lf", &celsius);
if(celsius < -273.15) {
NSLog(#"It is impossible to convert temperatures less than −273.15 degrees Celsius, because this is absolute zero, the coldest possible temperature.");
}
else {
[fahrenheitConversion convert: (((((celsius)*9)/5)+32))];
NSLog(#"%lf degrees Celsius is %lf Fahrenheit", celsius, [fahrenheitConversion formula]);
}
}
else {
NSLog(#"Please enter a temperature in Fahrenheit to be converted into Celsius!:\n");
scanf("%lf", &fahrenheit);
if(fahrenheit < -459.67) {
NSLog(#"It is impossible to convert temperatures less than −459.67 degrees Fahrenheit, because this is absolute zero, the coldest possible temperature.");
}
else {
[celsiusConversion convert: ((((fahrenheit - 32)/9)*5))];
NSLog(#"%lf degrees Fahrenheit is %lf Celsius", fahrenheit, [celsiusConversion formula]);
}
}
return 0;
}
How about this?
I tried not to change your code too much. It uses your original formulas and converter class, even though I was tempted to change it.
Screenshot:
alt text http://brockwoolf.com/shares/stackoverflow/3443063/tempcalc-iphone.png
Download Xcode project zipped (29kb)
Source Code:
ViewController interface:
#import <UIKit/UIKit.h>
#interface TempCalc_iPhoneViewController : UIViewController {
UITextField *celciusTextField;
UITextField *fahrenheitTextField;
UILabel *statusLabel;
double minFahrenheit;
double minCelcius;
NSString *normalStatus;
NSString *belowFahrenheitMessage;
NSString *belowCelciusMessage;
}
#property (nonatomic,retain) IBOutlet UITextField *celciusTextField;
#property (nonatomic,retain) IBOutlet UITextField *fahrenheitTextField;
#property (nonatomic,retain) IBOutlet UILabel *statusLabel;
- (IBAction) convertCelciusToFahrenheit:(UITextField*)sender;
- (IBAction) convertFahrenheitToCelcius:(UITextField*)sender;
#end
ViewController implementation
#import "TempCalc_iPhoneViewController.h"
#import "Converter.h"
#implementation TempCalc_iPhoneViewController
#synthesize celciusTextField, fahrenheitTextField, statusLabel;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
minCelcius = -273.15;
minFahrenheit = -459.67;
normalStatus = #"Please type to convert temperature";
belowFahrenheitMessage = #"impossible to convert temperatures less than −459.67 degrees Fahrenheit";
belowCelciusMessage = #"impossible to convert temperatures less than −273.15 degrees Celsius";
}
// Delegate method
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField
{
NSLog(#"User pressed the DONE button on the keyboard (any keyboard!)");
[theTextField resignFirstResponder];
return YES;
}
- (IBAction) convertCelciusToFahrenheit:(UITextField*)sender
{
Converter *celciusConversion = [[Converter alloc] init];
double celcius = [sender.text doubleValue];
if(celcius < minCelcius) {
NSLog(#"It is impossible to convert temperatures less than −273.15 degrees Celsius, because this is absolute zero, the coldest possible temperature.");
self.statusLabel.text = belowCelciusMessage;
}
else
{
[celciusConversion convert: ((((celcius)*9)/5)+32)];
NSString *fahrenheitValue = [NSString stringWithFormat:#"%lf", [celciusConversion formula]];
NSLog(#"%lf degrees Celsius is %# Fahrenheit", celcius, fahrenheitValue);
self.fahrenheitTextField.text = fahrenheitValue;
self.statusLabel.text = normalStatus;
}
[celciusConversion release];
}
- (IBAction) convertFahrenheitToCelcius:(UITextField*)sender
{
Converter *fahrenheitConversion = [[Converter alloc] init];
double fahrenheit = [sender.text doubleValue];
if(fahrenheit < minFahrenheit) {
NSLog(#"It is impossible to convert temperatures less than −459.67 degrees Fahrenheit, because this is absolute zero, the coldest possible temperature.");
self.statusLabel.text = belowFahrenheitMessage;
}
else {
[fahrenheitConversion convert: (((fahrenheit - 32)/9)*5)];
NSString *celciusValue = [NSString stringWithFormat:#"%lf", [fahrenheitConversion formula]];
NSLog(#"%lf degrees Fahrenheit is %# Celsius", fahrenheit, celciusValue);
self.celciusTextField.text = celciusValue;
self.statusLabel.text = normalStatus; }
[fahrenheitConversion release];
}
Porting it should be really simple. Apple provides some good sample apps. your fastest road to success is probably to download a simple textfield + button sample and add your calculations. Excluding the time it takes to download and install you'll have it ready in 1-2 hours.
Good luck!
Related
Trying to set an int value using a Segmented Controller. I've seen several tuts on how to change labels, but I need to set an int value.
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize caseCost;
#synthesize dilution;
#synthesize returnMsg;
#synthesize opcValue;
//synthesize opc; < -- Tried
//int opc; <--- tried
- (IBAction)opcView:(id)sender {
if (opcValue.selectedSegmentIndex == 0) {
int opc = 320;
}
if (opcValue.selectedSegmentIndex == 1) {
int opc = 128;
}
if (opcValue.selectedSegmentIndex == 2) {
int opc = 135;
}
if (opcValue.selectedSegmentIndex == 3) {
int opc = 88;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//int opc; <--- tried
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)finishBtn:(id)sender {
//int opc = 320;
float case_cost = ([caseCost.text floatValue]);
float dilutionValue = ([dilution.text floatValue]);
float gpc = (opc / dilutionValue);
float gCost = (case_cost / gpc);
float bCost = (gCost / 4);
float bpc = (gpc * 4);
NSNumberFormatter *formatterCur = [[NSNumberFormatter alloc] init];
NSNumberFormatter *formatterInt = [[NSNumberFormatter alloc] init];
[formatterCur setNumberStyle:NSNumberFormatterCurrencyStyle];
[formatterInt setNumberStyle:NSNumberFormatterDecimalStyle];
NSString *bottlesCost = [formatterCur stringFromNumber:[NSNumber numberWithFloat:bCost]];
NSString *gallons = [formatterInt stringFromNumber:[NSNumber numberWithInt:gpc]];
NSString *gallonsCost = [formatterCur stringFromNumber:[NSNumber numberWithFloat:gCost]];
NSString *bottles = [formatterInt stringFromNumber:[NSNumber numberWithInt:bpc]];
returnMsg.text = [NSString stringWithFormat:#"%# gallons per case at %# per gallon and %# - 32 oz bottles at %# per bottle.", gallons, gallonsCost, bottles, bottlesCost];
}
- (IBAction)opcView:(id)sender {
}
#end
in the line "float gpc = (opc / dilutionValue);" is shows as an unknown value of opc, even though I think it should from the segmented controller. I'm using the segmented controller instead of Radio Buttons i've used in Java. I used the "//int opc=320" to make sure the rest of the code worked.
In each of the if blocks in your method - (IBAction)opcView:(id)sender you are creating a local int variable named opc. So when execution leaves the if block, the local variable disappears. Thus, in - (IBAction)finishBtn:(id)sender there is no variable named opc in scope.
You should declare opc to be a property as well. You will set this property when the segment control changes selection. Later, you can read the property's value in your finish button's handler.
#import "SecondViewController.h"
#interface SecondViewController()
#property (nonatomic) int opc;
#end
#implementation SecondViewController
// this method is wired to the segment control's UIControlEventValueChanged event
- (IBAction)opcView:(id)sender
{
if (opcValue.selectedSegmentIndex == 0) {
self.opc = 320;
}
if (opcValue.selectedSegmentIndex == 1) {
self.opc = 128;
}
if (opcValue.selectedSegmentIndex == 2) {
self.opc = 135;
}
if (opcValue.selectedSegmentIndex == 3) {
self.opc = 88;
}
}
- (IBAction)finishBtn:(id)sender
{
float case_cost = ([caseCost.text floatValue]);
float dilutionValue = ([dilution.text floatValue]);
float gpc = (self.opc / dilutionValue);
// lots more code
}
I'm following the Stanford course, and we had to build a method for the app that checks for 2 cards matching, this is how the model that have the logic looks like (the method to look there is flipCardAtIndex):
#import "CardMatchingGame.h"
#import "PlayingCardsDeck.h"
#interface CardMatchingGame()
#property (readwrite, nonatomic) int score;
#property (strong, nonatomic) NSMutableArray *cards;
#property (strong, nonatomic) NSString *notification;
#end
#implementation CardMatchingGame
-(NSMutableArray *) cards {
if (!_cards) _cards = [[NSMutableArray alloc] init];
return _cards;
}
-(id)initWithCardCount:(NSUInteger)count usingDeck:(Deck *)deck {
self = [super init];
if (self) {
for (int i = 0; i < count; i++) {
Card *card = [deck drawRandonCard];
if (!card) {
self = nil;
} else {
self.cards[i] = card;
}
}
}
return self;
}
-(Card *) cardAtIndex:(NSUInteger)index {
return (index < self.cards.count) ? self.cards[index] : nil;
}
#define FLIP_COST 1
#define MISMATCH_PENALTY 2
#define BONUS 4
-(void) flipCardAtIndex:(NSUInteger)index {
Card *card = [self cardAtIndex:index];
if (!card.isUnplayable) {
if (!card.isFaceUp) {
for (Card *otherCard in self.cards) {
if (otherCard.isFaceUp && !otherCard.isUnplayable) {
int matchScore = [card match:#[otherCard]];
if (matchScore) {
otherCard.unplayble = YES;
card.unplayble = YES;
self.notification = [NSString stringWithFormat:#"%# & %# match!", card.contents, otherCard.contents];
self.score += matchScore * BONUS;
} else {
otherCard.faceUp = NO;
self.score -= MISMATCH_PENALTY;
self.notification = [NSString stringWithFormat:#"%# did not matched to %#", card.contents, otherCard.contents];
}
break;
}
}
self.score -= FLIP_COST;
}
card.faceUp = !card.isFaceUp;
}
}
#end
And this is the class model of the whole game, that got the actual matching method:
#import "PlayingCards.h"
#implementation PlayingCards
#synthesize suit = _suit;
//overriding the :match method of cards to give different acore if its only a suit match or a number match
-(int)match:(NSArray *)cardToMatch {
int score = 0;
if (cardToMatch.count == 1) {
PlayingCards *aCard = [cardToMatch lastObject];
if ([aCard.suit isEqualToString: self.suit]) {
score = 1;
} else if (aCard.rank == self.rank) {
score = 4;
}
}
return score;
}
//more stuff...
W already created it with an array so we will be able to extend it for more objects, but now i'm trying to figure out how do I extend it :/
This is my github for the project https://github.com/NirOhayon/Matchismo
i'm new to objective C and would appreciate it munch if you could help me to figure it out.
Thanks a bunch
You can chain these with a loop to check them all. Very basic way of doing it. Just loop through each card and check it against the "self" card that you have and increment the score instead of setting it.
-(int)match:(NSArray *)cardToMatch {
int score = 0;
for(int i = 0; i < cardToMatch.count; i++) {
PlayingCards *aCard = cardToMatch[i];
if ([aCard.suit isEqualToString: self.suit]) {
score += 1;
} else if (aCard.rank == self.rank) {
score += 4;
}
}
return score;
}
For flipCardAtIndex: , I would change it to flipCardsAtIndexes:(NSArray*)indexes, where indexes is an NSArray of NSNumbers. Then I would run a for loop checking and removing any cards that are unplayable or faceup, and pass through the remaining cards at those indexes to check match, and retrieve the match score.
To tell your view controller to add another card depends on how you have your view controller set up. You could do a protocol in a method that your view controller becomes the delegate of, and through a protocol method, tell it to switch. It could also be simpler than that, depending on how it checks your model of cards to decide what to show, if it sees three cards available instead of two, it could switch.
As the point of this exercise is to learn iOS programming, I want to give you a good head start and you should tweak and figure some stuff out on your own. I have a feeling you're a novice at programming, and if you are, you'll be surprised how much programming at your stage is trial and error. Eventually it will become second nature.
all. I'm trying to follow a tutorial on making a ball bounce around the screen of an iPhone. The tutorial constructs the application in a MVC scheme. I'm having trouble wrapping my head around this concept when it comes to the drawRect method in the View implementation.
This is my Model header file:
#import <Foundation/Foundation.h>
#import "TestView.h"
#define BALL_SIZE 20.0
#define VIEW_WIDTH 320.0
#define VIEW_HEIGHT 460.0
#interface TestModel : NSObject
{
TestView* ball;
CGPoint ballVelocity;
CGFloat lastTime;
CGFloat timeDelta;
}
- (void) updateModelWithTime:(CFTimeInterval) timestamp;
- (void) checkCollisionWithScreenEdges;
#property (readonly) TestView* ball;
#end
The tutorial instructs me the user to override the init method of NSObject. I've also included the methods for controlling the "animation" logic:
- (id) init {
self = [super init];
if (self) {
ball = [[TestView alloc] initWithFrame: CGRectMake(0.0, 0.0, BALL_SIZE, BALL_SIZE)];
// Set the initial velocity for the ball
ballVelocity = CGPointMake(200.0, -200.0);
// Initialize the last time
lastTime = 0.0;
}
return self;
}
- (void) checkCollisionWithScreenEdges {
// Left Edge
if (ball.frame.origin.x <= 0) {
ballVelocity.x = abs(ballVelocity.x);
}
// Right Edge
if (ball.frame.origin.x >= VIEW_WIDTH - BALL_SIZE) {
ballVelocity.x = -1 * abs(ballVelocity.x);
}
// Top Edge
if (ball.frame.origin.y <= 0) {
ballVelocity.y = abs(ballVelocity.y);
}
// Bottom Edge
if (ball.frame.origin.y >= VIEW_HEIGHT - BALL_SIZE) {
ballVelocity.y = -1 * abs(ballVelocity.y);
}
}
- (void) updateModelWithTime:(CFTimeInterval) timestamp {
if (lastTime == 0.0) {
// initialize lastTime if first time through
lastTime = timestamp;
} else {
// Calculate time elapsed since last call
timeDelta = timestamp - lastTime;
// Update the lastTime
lastTime = timestamp;
[self checkCollisionWithScreenEdges];
// Calculate the new position of the ball
CGFloat x = ball.frame.origin.x + ballVelocity.x * timeDelta;
CGFloat y = ball.frame.origin.y + ballVelocity.y * timeDelta;
ball.frame = CGRectMake(x, y, BALL_SIZE, BALL_SIZE);
}
}
The View implementation file is the following:
#import "TestView.h"
#implementation TestView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect) rect {
}
#end
Finally, my View Controller:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
gameModel = [[TestModel alloc] init];
[self.view addSubview:gameModel.ball];
// Set up the CADisplayLink for the animation
gameTimer = [CADisplayLink displayLinkWithTarget:self selector:#selector(updateDisplay:)];
// Add the display link to the current run loop
[gameTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void) updateDisplay:(CADisplayLink *) sender {
[gameModel updateModelWithTime:sender.timestamp];
}
OK, so now that I've provided a look at the structure of the code (hopefully I've given enough) I can get to my question. So when I add anything to drawRect a new object is drawn and does not get "animated" by the model logic methods.
Right now I have a bouncing square. When I try to fill the square with an ellipse in drawRect, I get a new object, drawn how I want, that just sits at 0,0 while the bouncing square is still active.
I'm sure I'm missing something really big here, but I've been banging my head against the wall for hours and can't figure it out. Any help would be greatly appreciated!
A couple of things here:
1- Have you overriden the view class in SB to TestView?
2- Looking at your code, I do not see how your model is connected to your View through your controller. Recall from the MVC model, that the Controller is on top and talks down (pyramid style) to the model and the view and so, somewhere in your view controller:
a) you need to instantiate your model
b) get values from your model and pass them to your view variables - which would be called in drawrect
Last but not least, lookup setNeedsDisplay which is the way to call and refresh the view.
Hope this helps without spoiling the assignment.
I was wondering on how do I increase the interval over time so I can add target. I am still new to cocos2d.
[self schedule:#selector(gameLogic:) interval:0.7];
-(void)gameLogic:(ccTime)dt {
[self addTarget];
}
Why not declare a simple property (int, float, etc.) to hold the number of times your method has been called, and increment it when you call the method itself? That way, it's just a multiplication problem:
//.h
...
#property (nonatomic, assign) int iterations;
//.m
#synthesize iterations = iterations_;
[self schedule:#selector(gameLogic:) interval:0.7*iterations_];
-(void)gameLogic:(ccTime)dt {
[self addTarget];
iterations_++;
}
float interval = .7;
-(id)init{
...
[self scheduleOnce:#selector(gameLogic:) delay:interval]; //Check the name of the method, I'm not 100% sure about it
...
}
-(void)gameLogic:(ccTime)dt {
[self addTarget];
interval += dt; //Or whatever you want to increase it by
[self scheduleOnce:#selector(gameLogic:) delay:interval]; //Check the name of the method, I'm not 100% sure about it
}
i had made an application of temperature converter in iphone i want that when it launches in simulator only numeric keyboard should come and not the alpha keyboard.
#import "farh_celcius_conv_AppDelegate.h"
float i;
float s;
float p;
#implementation farh_celcius_conv_AppDelegate
#synthesize window,display,farhenite,display1;
-(IBAction) convert {
s = ('0','1','2');
if( p == s)
{
NSString *str = farhenite. text;
float n = [str floatValue];
if (n != 0) {
k =.5559* (n-32);
i = 5*(n -32)/9 +273 ;
[display setText:[NSString stringWithFormat:#"%f",k]];
[display1 setText:[NSString stringWithFormat:#"%f",i]];
}
}
}
- (void)dealloc {
[window release];
[super dealloc];
}
#end
You can set various types of keyboard for your text field. Look into inspector under Text Input traits, keyboard.
Try this,
yourTextField.keyboardType = UIKeyboardTypePhonePad;
or
yourTextField.keyboardType = UIKeyboardTypeNumberPad;
You can also do this in the nib file.
[myTextField setKeyboardType:UIKeyboardTypeNumberPad];