I'm working on the following code, which has the steps of a person walking. but every time I step from one view to another the counter stops. I am working with SOMotionDetector.
NOTE: when printing to console the steps that continues to function even changing views.
#import "SOMotionDetector.h"
#import "SOStepDetector.h"
#interface ContarPasos ()<SOMotionDetectorDelegate>
{
int stepCount;
}
#property (weak, nonatomic) IBOutlet UILabel *speedLabel;
#property (weak, nonatomic) IBOutlet UILabel *stepCountLabel;
#property (weak, nonatomic) IBOutlet UILabel *motionTypeLabel;
#property (weak, nonatomic) IBOutlet UILabel *isShakingLabel;
#end
#implementation ContarPasos
- (void)viewDidLoad
{
[super viewDidLoad];
__strong ContarPasos *weakSelf = self;
[SOMotionDetector sharedInstance].motionTypeChangedBlock = ^(SOMotionType motionType) {
NSString *type = #"";
switch (motionType) {
case MotionTypeNotMoving:
type = #"No estas moviendote";
break;
case MotionTypeWalking:
type = #"Caminando";
break;
case MotionTypeRunning:
type = #"Corriendo";
break;
case MotionTypeAutomotive:
type = #"Automotive";
break;
}
weakSelf.motionTypeLabel.text = type;
};
[SOMotionDetector sharedInstance].locationChangedBlock = ^(CLLocation *location) {
weakSelf.speedLabel.text = [NSString stringWithFormat:#"%.2f km/h", [SOMotionDetector sharedInstance].currentSpeed * 3.6f];
};
[SOMotionDetector sharedInstance].accelerationChangedBlock = ^(CMAcceleration acceleration) {
BOOL isShaking = [SOMotionDetector sharedInstance].isShaking;
weakSelf.isShakingLabel.text = isShaking ? #"Corriendo":#"No corriendo";
};
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
[SOMotionDetector sharedInstance].useM7IfAvailable = YES; //Use M7 chip if available, otherwise use lib's algorithm
}
[[SOMotionDetector sharedInstance] startDetection];
[[SOStepDetector sharedInstance] startDetectionWithUpdateBlock:^(NSError *error) {
if (error) {
NSLog(#"%#", error.localizedDescription);
return;
}
stepCount++;
weakSelf.stepCountLabel.text = [NSString stringWithFormat:#"Pasos: %d", stepCount];
NSLog(#"always printed on console but not in the view: %d", stepCount);
}];
}
Related
Here is my button function where I pass the data.
The problem is Area and Country details are passed to the next ViewController but latitude and longitude return null.
In ViewController.m :
- (IBAction)forecast:(UIButton *)sender
{
ForecastViewController *sendDetails = [[ForecastViewController alloc] init];
NSArray *seperate = [full componentsSeparatedByString:#", "];
Area = seperate[0];
Country = seperate[1];
sendDetails.Area = Area;
sendDetails.Country = Country;
NSLog(#"%#%#",self.longitude,self.latitude);
NSString *lt = self.latitude;
NSString *ln = self.longitude;
sendDetails.longitude = lt;
sendDetails.latitude = ln;
}
In ForecastViewController.h
//
// ForecastViewController.h
// Weather App
//
// Created by Mac-Mini-2 on 10/02/16.
// Copyright © 2016 Mac-Mini-2. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#import <Reachability.h>
#interface ForecastViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UILabel *place;
#property (weak, nonatomic) IBOutlet UITableView *table;
#property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator;
#property NSString *Area;
#property NSString *Country;
#property NSString *latitude;
#property NSString *longitude;
#end
In ForecastViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.table.delegate = self;
self.table.dataSource = self;
self.place.text = [NSString stringWithFormat:#"%#, %#",self.Area,self.Country];
locationName = [NSString stringWithFormat:#"%#, %#",self.Area,self.Country];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
metric = [defaults boolForKey:#"metric"];
Reachability *reach = [Reachability reachabilityWithHostName:#"www.google.com"];
NSInteger x = [reach currentReachabilityStatus];
if (x > 0)
{
reachable = YES;
NSLog(#"%#, %#",self.latitude,self.longitude);
[self getForecast:self.latitude longitudes:self.longitude];
}
else
{
reachable = NO;
[self getData];
errorMsg = #"Because of unavailability of Network Realtime information wont be available.";
[self performSelectorOnMainThread:#selector(displayAlert) withObject:NULL waitUntilDone:YES];
}
[reach startNotifier];
}
Please let me know where I could have gone wrong here.
I checked by logging the data onto console. The area and country is printed but longitude and latitude give null values.
if you are doing a push to ForecastViewController, maybe implementing prepareForSegue:sender: is your best option.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"viewForecast"]){
NSArray *seperate = [full componentsSeparatedByString:#", "];
Area = seperate[0];
Country = seperate[1];
[(ForecastViewController *) [segue destinationViewController] setArea:area];
[(ForecastViewController *) [segue destinationViewController] setCountry:country];
...
...
}
}
Could I the that latitude and longitude are stored as numbers in the first controller? Are you sure that 'sendDetails.latitude' and 'longitude' are set correctly in 'ViewController'?
I think you need to edit two point firstly in ForecastViewController.h set
#property (Strong, nonatomic) NSString *Area;
#property (Strong, nonatomic) NSString *Country;
#property (Strong, nonatomic) NSString *latitude;
#property (Strong, nonatomic) NSString *longitude;
and #synthsize it in ForecastViewController.m.
secondly:-
- (IBAction)forecast:(UIButton *)sender
{
ForecastViewController *sendDetails = [self.storyboard instantiateViewControllerWithIdentifier:#"your ForecastViewController name in storyboard"];
NSArray *seperate = [full componentsSeparatedByString:#", "];
Area = seperate[0];
Country = seperate[1];
sendDetails.Area = Area;
sendDetails.Country = Country;
NSLog(#"%#%#",self.longitude,self.latitude);
NSString *lt = self.latitude;
NSString *ln = self.longitude;
sendDetails.longitude = lt;
sendDetails.latitude = ln;
[self.navigationController pushViewController:sendDetails animated:YES];
}
So i recently implemented parallax images into my app which works great, however this has broken a button which calls a method.
Here is a picture of my storyboard:
http://imgur.com/uIonWrK
Here is my .h code:
#interface _01FirstViewController : UIViewController <UITextFieldDelegate, UIAccelerometerDelegate>{
UIAccelerometer *accelerometer;
float xoof;
float yoff;
float xvelocity;
float yvelocity;
float xaccel;
float yaccel;
}
#property (nonatomic, retain) UIAccelerometer *accelerometer;
#property (weak, nonatomic) IBOutlet UIScrollView *BGScrollView;
#property (weak, nonatomic) IBOutlet UIButton *Track;
#property (weak, nonatomic) IBOutlet UITextField *trackingNumber;
#property (strong, nonatomic) NSDictionary *posts;
#property (strong,nonatomic) NSString *TrackPoint;
#property (strong,nonatomic) NSArray *Path;
#property (strong,nonatomic) NSString *documentFolder;
#property (strong,nonatomic) NSString *filePath;
-(void)parseTrackNo;
-(void)reloadTrackingNumber;
Here is the relevant parts of the .m:
- (void)viewDidLoad
{
_BGScrollView.contentSize = CGSizeMake(_BGScrollView.frame.size.width+30,_BGScrollView.frame.size.width+30);
self.accelerometer = [UIAccelerometer sharedAccelerometer];
self.accelerometer.updateInterval = 0.03;
self.accelerometer.delegate = self;
[NSTimer scheduledTimerWithTimeInterval:-1 target:self selector:#selector(tick) userInfo:nil repeats:YES];
}
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
float xx = -acceleration.x;
float yy = (acceleration.y + 0.5f) *2.0f;
float acceldirX;
if (xvelocity * -1.0f >0){
acceldirX = 1.0;
}
else {
acceldirX = -1.0;
}
float newdirX;
if (xx > 0){
newdirX = 1.0;
}
else {
newdirX = -1.0;
}
float acceldirY;
if (yvelocity * -1.0f >0){
acceldirY = 1.0;
}
else {
acceldirY = -1.0;
}
float newDirY;
if (yy > 0){
newDirY = 1.0;
}
else {
newDirY = -1.0;
}
if (acceldirX == newdirX) xoof = acceleration.x * 30;
if (acceldirY == newDirY) yoff = acceleration.y *30;
}
This is the button that has stopped calling the method:
- (IBAction)Track:(id)sender {
[self parseTrackNo]; //Not calling method
NSLog(#"Button Pressed"); //This gets logged correctly
}
I have tried removing all code changes so i suspect it is something to do with the button being nested inside the view in the storyboard or the delegate changes.
Can anyone point me in the correct direction?
EDIT as requested the code for parseTrackingNo (note this was working perfectly until the parallax changes):
-(void)parseTrackNo
{
_01AppDelegate *appDelegate = (_01AppDelegate *)[[UIApplication sharedApplication] delegate];
//Get Tracking Number from textField
appDelegate.TrackingNumber = _trackingNumber.text;
//Check String isn't empty
if ([_trackingNumber.text isEqual: #""]){
} else{
//Check against Royal Mail API
NSString *trackingURL = [NSString stringWithFormat:#"%#%#", #"http://api.e44.co/tracktrace/", appDelegate.TrackingNumber];
NSURL *royalMail = [NSURL URLWithString:trackingURL];
//Return results
NSData *royalMailResults = [NSData dataWithContentsOfURL:royalMail];
//Parse JSON results
if(royalMailResults != nil)
{
NSError *error = nil;
id result = [NSJSONSerialization JSONObjectWithData:royalMailResults options:NSJSONReadingMutableContainers error:&error];
if (error == nil)
//Convert to dictionary/array
self.posts = (NSDictionary *)result;
NSArray *trackRecords = _posts[#"trackRecords"];
//Return keys from posts (Dict)
NSString *response = [self.posts valueForKeyPath:#"response"];
NSLog(#"Response: %#", response);
NSString *returnedTrackingNumber = [self.posts valueForKeyPath:#"trackingNumber"];
NSLog(#"Returned tracking number: %#", returnedTrackingNumber);
NSString *delivered = [self.posts valueForKeyPath:#"delivered"];
NSLog(#"delivered: %#", delivered);
NSString *signature = [self.posts valueForKeyPath:#"signature"];
NSLog(#"Signature: %#", signature);
//Track Records
NSString *Date = [trackRecords valueForKeyPath:#"date"];
NSLog(#"date: %#", Date);
NSString *Time = [trackRecords valueForKeyPath:#"time"];
NSLog(#"time: %#", Time);
NSString *Status = [trackRecords valueForKeyPath:#"status"];
NSLog(#"status: %#", Status);
appDelegate.LocationData = [[trackRecords valueForKey:#"trackPoint"] componentsJoinedByString:#""];
NSLog(#"GeoLocation: %#", appDelegate.LocationData);
//Check for Errors returned
if ([self.posts objectForKey:#"errorMsg"]) {
NSLog(#"ERROR MOTHERFUCKER");
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Error"
message:#"It appears that you have entered an incorrect tracking number"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alert show];
} else {
[self performSegueWithIdentifier:#"addPackageSegue" sender:self];
}
}
}
}
I was trying to solve assignment 2 from Stanford iOS7 development (Matchismo card game)
The game works fine. Now I have to add the Restart function. If the user press on the restart button, the game restarts (it deals new cards and it resets the score)
my game model is the #property (nonatomic, strong) CardMatchingGame *game;
this is the code for the CardMatchingGame.m:
#import "CardMatchingGame.h"
#import "PlayingCardDeck.h"
#interface CardMatchingGame()
#property (nonatomic, readwrite) NSInteger score;
#property (nonatomic, strong) NSMutableArray *cards;
#end
#implementation CardMatchingGame
static const int MATCH_BONUS = 4;
static const int MATCH_PENALTY = 2;
static const int COST_TO_CHOOSE = 1;
-(NSMutableArray *)cards{
if(!_cards) _cards = [[NSMutableArray alloc]init];
return _cards;
}
-(instancetype)initWithCardCount:(NSUInteger)count usingDeck:(Deck *)deck{
self = [super init];
if(self){
for(int i=0; i < count; i++){
Card *card = [deck drawRandomCard];
if(card){
[self.cards addObject:card];
} else{
self = nil;
break;
}
}
}
return self;
}
-(void)chooseCardAtIndex:(NSUInteger)index{
Card *card = [self cardAtIndex:index];
if(!card.isMatched){
if(card.isChosen){
card.chosen = NO;
} else{
for(Card *otherCard in self.cards){
if(otherCard.isChosen && !otherCard.isMatched){
int matchScore = [card match:#[otherCard]];
if(matchScore){
self.score += matchScore * MATCH_BONUS;
card.matched = YES;
otherCard.matched = YES;
} else{
self.score -= MATCH_PENALTY;
otherCard.chosen = NO;
}
break;
}
}
self.score -= COST_TO_CHOOSE;
card.chosen = YES;
}
}
}
-(Card *)cardAtIndex:(NSUInteger)index{
return (index < [self.cards count]) ? self.cards[index] : nil;
}
#end
here is my CardGameViewController.m:
#import "CardGameViewController.h"
#import "PlayingCardDeck.h"
#import "CardMatchingGame.h"
#interface CardGameViewController ()
#property (nonatomic, strong) Deck *deck;
#property (nonatomic, strong) CardMatchingGame *game;
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *cardsCollection;
#property (weak, nonatomic) IBOutlet UILabel *scoreLabel;
#end
#implementation CardGameViewController
#synthesize game = _game;
-(CardMatchingGame *)game{
if(!_game) _game = [[CardMatchingGame alloc] initWithCardCount:[self.cardsCollection count]
usingDeck:self.deck];
return _game;
}
-(Deck *)deck{
if(!_deck) _deck = [[PlayingCardDeck alloc] init];
return _deck;
}
- (IBAction)touchRestartButton:(id)sender {
self.game = nil;
[self updateUI];
}
- (IBAction)touchCardButton:(UIButton *)sender {
int chosenButtonIndex = [self.cardsCollection indexOfObject:sender];
[self.game chooseCardAtIndex:chosenButtonIndex];
[self updateUI];
}
-(void)updateUI{
for(UIButton *cardButton in self.cardsCollection){
int buttonIndex = [self.cardsCollection indexOfObject:cardButton];
Card *card = [self.game cardAtIndex:buttonIndex];
[cardButton setTitle:[self titleForCard:card] forState:UIControlStateNormal];
[cardButton setBackgroundImage:[self backgroundImageForCard:card] forState:UIControlStateNormal];
cardButton.enabled = !card.isMatched;
}
self.scoreLabel.text = [NSString stringWithFormat:#"Score: %d", self.game.score];
}
-(NSString *)titleForCard:(Card *)card{
return card.isChosen ? card.contents : #"";
}
-(UIImage *)backgroundImageForCard:(Card *)card{
return [UIImage imageNamed: card.isChosen ? #"cardfront" : #"cardback"];
}
#end
In order to restart the game, I think I should simply re-initialize the property CardMatchingGame *game.
This is what I tried to do, by setting self.game = nil; Then it should automatically be re-initialized in the getter of game.
This is, indeed, the solution that I found on the internet. However, in my program it doesn't work. *game is set to nil and never restored, so the game ends when you click restart.
Could you please help me to figure out why self.game = nil doesn't work in my case?
- (IBAction)startover:(UIButton *)sender {
self.game= [[CardMatchingGame alloc] initWithCardCount:[self.cardButtons count] usingDeck:[self createDeck]];
[self updateUI];
}
If your program has the lazy init style recommended, there is no need for a new method such as start over. You are correct to set self.game to nil, now a call the the getter will start a new instance of the game. I did it by making a call to UIUpdate right after the self.game = nil. That has a call to the getter and lazily inits a new instance of the game.
I made a button in storyboard and associated it with an IBAction in my header file. How can I set the title of this button to the variable I made displayPhone and have it call that number as well?
.h
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#interface IBThirdViewController : UIViewController
#property (nonatomic, strong) PFRelation *agentRelation;
#property (nonatomic, strong) NSArray *agent;
#property (weak, nonatomic) IBOutlet UILabel *agentName;
#property (strong, nonatomic) IBOutlet UILabel *agentPhone;
#property (strong, nonatomic) IBOutlet UILabel *agentEmail;
#property (strong, nonatomic) IBOutlet UIImageView *agentImage;
- (IBAction)phoneButton:(id)sender;
#end
.m
#import "IBThirdViewController.h"
#import "IBAgentsTableViewController.h"
#interface IBThirdViewController ()
#end
#implementation IBThirdViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
//Find the Agent and show it
self.agentRelation = [[PFUser currentUser] objectForKey:#"agentRelation"];
PFQuery *query = [self.agentRelation query];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// success
self.agent = objects;
// Do something with the found objects
for (PFObject *object in objects) {
NSLog(#"name: %#", [object objectForKey:#"name"]);
NSLog(#"email: %#", [object objectForKey:#"email"]);
NSString *displayEmail = [object objectForKey:#"email"];
NSString *displayName = [object objectForKey:#"name"];
NSString *displayPhone = [object objectForKey:#"phone"];
PFFile *thumbnail = [object objectForKey:#"profilePic"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:thumbnail.url];
NSData *imageData = [NSData dataWithContentsOfURL:imageFileURL];
self.agentEmail.text = displayEmail;
self.agentName.text = displayName;
self.agentPhone.text = displayPhone;
self.agentImage.image = [UIImage imageWithData:imageData];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showEditAgent"]) {
IBAgentsTableViewController *viewController = (IBAgentsTableViewController *)segue.destinationViewController;
viewController.agents = [NSMutableArray arrayWithArray:self.agent];
}
}
- (IBAction)phoneButton:(id)sender {
}
#end
First of all you need connect button from xib with IBOutlet object:
#property (nonatomic, weak) IBOutlet UIButton *displayPhone;
Then set it's title in -(void)viewDidAppear:(BOOL)animated after loading data:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
//...
// Load data here
//...
[self.displayPhone setTitle:displayPhone forState:UIControlStateNormal];
}
Finally implement IBAction method for button:
- (IBAction)phoneButton:(id)sender {
NSString *phone = [sender titleForState:UIControlStateNormal];
// Remove all chars except of digits
static NSString *const kDigitsString = #"0123456789";
phone = [[phone componentsSeparatedByCharactersInSet:[[NSCharacterSet characterSetWithCharactersInString:kDigitsString] invertedSet]] componentsJoinedByString:#""];
// Initiate call
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:#"tel:%#", phone]]];
}
It looks like you haven't connected the button to an outlet but only to an action.
First you need to connect it to an outlet (like you've done with the labels).
Then use...
[self.button setTitle:#"blah" forState:UIViewControlStateNormal];
Something like that anyway. I'm currently on my iPhone so I don't have auto complete.
If you want to change the title inside the IBAction method do:
[sender setTitle:#"My title" forState:UIControlStateNormal];
If you want to change in any other place you need a #property of uibutton, something like this
#property (strong, nonatomic) IBOutlet UIButton *phoneButtonProperty;
and connect it to your button and then
[phoneButtonProperty setTitle:#"My title" forState:UIControlStateNormal];
Please help....I'm losing my mind trying to figure out this problem.
I'm fairly new to iOS so don't go too hard on me if it's something obvious! ;)
I'm using xcode 4.6 and targeting iPhone6.1 Simulator.
I get the following error when starting up my app:
EXC_BAD_ACCESS code = 2
There are hundres of threads appearing in Debug Navigator which leads to to believe there is some sort of infinite loop somewhere (I just cannot see where).
The error occurs beside (id)init in PlayingCardDeck.m after entering it from ViewController.m at line:
Card *card = [self.deck drawRandonCard];
ViewConrtoller:
#import "ViewController.h"
#import "PlayingCardDeck.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UILabel *flipsLabel;
#property (nonatomic) int flipCount;
#property (strong, nonatomic) Deck *deck;
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *cardButtons;
#end
#implementation ViewController
#synthesize deck = _deck;
- (IBAction)flipCard:(UIButton *)sender {
sender.selected = !sender.isSelected;
self.flipCount++;
}
- (void)setFlipCount:(int)flipCount
{
_flipCount = flipCount;
self.flipsLabel.text = [NSString stringWithFormat:#"Flips: %d", self.flipCount];
}
- (Deck *)deck
{
if (!_deck) _deck = [[PlayingCardDeck alloc] init];
return _deck;
}
- (void)setCardButtons:(NSArray *)cardButtons
{
_cardButtons = cardButtons;
for (UIButton *cardButton in cardButtons)
{
Card *card = [self.deck drawRandonCard];
[cardButton setTitle:card.contents forState:UIControlStateSelected];
}
}
#end
Deck.m
#import "Deck.h"
#interface Deck()
#property (strong, nonatomic) NSMutableArray *cards;
#end
#implementation Deck
- (NSMutableArray *)cards
{
if (!_cards) _cards = [[NSMutableArray alloc] init];
return _cards;
}
- (void)addCard:(Card *)card atTop:(BOOL)atTop
{
if (atTop)
{
[self.cards insertObject:card atIndex:0];
}
else
{
[self.cards addObject:card];
}
}
- (Card *)drawRandonCard
{
Card *randomCard = nil;
if (self.cards.count)
{
unsigned index = arc4random() % self.cards.count;
randomCard = self.cards[index];
[self.cards removeObjectAtIndex:index];
}
return randomCard;
}
#end
PlayingCardDeck.m
#import "PlayingCardDeck.h"
#import "PlayingCard.h"
#implementation PlayingCardDeck
- (id)init
{
self = [self init];
if (self)
{
for (NSString *suit in [PlayingCard validSuits])
{
for (NSUInteger rank=1; rank <= [PlayingCard maxRank]; rank++)
{
PlayingCard *card = [[PlayingCard alloc] init];
card.suit = suit;
card.rank = rank;
[self addCard:card atTop:YES];
}
}
}
return self;
}
#end
In PlayerCardDeck.m self = [self init] should be self = [super init]. That's causing the infinite loop.