- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSDateFormatter * formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateFormat:#"yyyy-MM-dd HH:mm"];
NSString *latitude = [NSString stringWithFormat:#"%f", newLocation.coordinate.latitude];
NSString *longitude = [NSString stringWithFormat:#"%f", newLocation.coordinate.longitude];
NSString *stringFromDate = [formatter stringFromDate:newLocation.timestamp];
resultsLabel.text = [NSString stringWithFormat:#"(%#) %# Location %.06f %.06f %#", ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) ? #"bg" : #"fg", resultsLabel.tag == 0 ? #"gps:" : #"sig" , newLocation.coordinate.latitude, newLocation.coordinate.longitude, [formatter stringFromDate:newLocation.timestamp]];
NSLog(#"%#", resultsLabel.text);
LocationTestAppDelegate * appDelegate = (LocationTestAppDelegate *)[UIApplication sharedApplication].delegate;
[appDelegate log:resultsLabel.text];
}
But i get this as output.
(null)
on :
NSLog(#"%#", resultsLabel.text);
Does anyone know what im doing wrong?
- (id) initWithLabel:(UILabel*)label
{
resultsLabel = label;
return [super init];
}
And in my delegate i set the resultLabel here:
- (void) log:(NSString*)msg
{
NSDateFormatter * formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setTimeStyle:NSDateFormatterMediumStyle];
NSString * logMessage = [NSString stringWithFormat:#"%# %#", [formatter stringFromDate:[NSDate date]], msg];
NSString * fileName = [self locationPath];
FILE * f = fopen([fileName UTF8String], "at");
fprintf(f, "%s\n", [logMessage UTF8String]);
fclose (f);}
EDIT
I deleted the GPS functionality.
Does anyone know how a proper NSLog would be in the newlocation. longitude latitude timestamp?
EDIT 2
I set the resultlabel here:
#interface LocationDelegate : NSObject <CLLocationManagerDelegate>
{
UILabel * resultsLabel;
NSString * _phonenumber;
}
- (id) initWithLabel:(UILabel*)label;
//-(id)initWithDictionary:(NSDictionary *)dict;
//-(id)initWithName:(NSString *)aName;
//-(NSDictionary *)toDictionary;
#property (nonatomic , retain) NSString *phonenumber;
Your init code is strange. This is more usual:
- (id) initWithLabel:(UILabel*)label
{
if (self = [super init]) {
resultsLabel = label; // Or maybe _resultsLabel, depending on your code
}
return self;
}
And then access what I presume is an instance variable through self.resultsLabel.
Presumably your problem is that resultsLabel is already nil when you try to set it's text. Sending a message to nil does nothing, not even give an error.
Related
So I'm building a calendar-type app on the new Apple iWatch. This is the initial storyboard layout for my app:
Basically the initial table view will parse the calendar and grab the event name and the date of it. What I want to do is basically, through a push segue, send that data to the second view controller.
I have tried using the method -(NSArray *)contextsForSegueWithIdentifier:(NSString *)segueIdentifier, but the context in the second view controller is showing up as nil.
This is my code:
InterfaceViewController:
#import "InterfaceController.h"
#import <EventKit/EventKit.h>
#import "Calendar.h"
#interface InterfaceController() {
NSArray *events;
NSArray *eventsWithNotes;
}
#end
#implementation InterfaceController
- (void)setupTable
{
EKEventStore *store = [[EKEventStore alloc] init];
// Get the appropriate calendar
NSCalendar *calendar = [NSCalendar currentCalendar];
if ([store respondsToSelector:#selector(requestAccessToEntityType:completion:)])
{
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error)
{
if (granted)
{
NSLog(#"User has granted permission!");
// Create the start date components
NSDateComponents *oneDayAgoComponents = [[NSDateComponents alloc] init];
oneDayAgoComponents.day = -1;
NSDate *oneDayAgo = [calendar dateByAddingComponents:oneDayAgoComponents
toDate:[NSDate date]
options:0];
// Create the end date components
NSDateComponents *oneYearFromNowComponents = [[NSDateComponents alloc] init];
oneYearFromNowComponents.year = 1;
NSDate *oneYearFromNow = [calendar dateByAddingComponents:oneYearFromNowComponents
toDate:[NSDate date]
options:0];
// Create the predicate from the event store's instance method
NSPredicate *predicate = [store predicateForEventsWithStartDate:oneDayAgo
endDate:oneYearFromNow
calendars:nil];
// Fetch all events that match the predicate
events = [store eventsMatchingPredicate:predicate];
NSMutableArray *rowTypesList = [NSMutableArray array];
for(int i=0; i < events.count; i++){
[rowTypesList addObject:#"Calendar"];
}
[self.tableView setRowTypes:rowTypesList];
for (NSInteger i = 0; i < self.tableView.numberOfRows; i++)
{
NSObject *row = [self.tableView rowControllerAtIndex:i];
Calendar *calendar = (Calendar *) row;
NSLog(#"notes: %#",[[events objectAtIndex:i] notes]);
NSString* notes = [[events objectAtIndex:i] notes];
[calendar.titleLabel setText:[[events objectAtIndex:i] title]];
}
}
else
{
NSLog(#"User has not granted permission!");
}
}];
}
}
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// Configure interface objects here.
}
- (void)willActivate {
// This method is called when watch view controller is about to be visible to user
[super willActivate];
[self setupTable];
}
- (void)didDeactivate {
// This method is called when watch view controller is no longer visible
[super didDeactivate];
}
- (NSArray *)contextsForSegueWithIdentifier:(NSString *)segueIdentifier inTable:(WKInterfaceTable *)table rowIndex:(NSInteger)rowIndex {
NSArray *array = nil;
NSString *notes = [[events objectAtIndex:rowIndex] notes];
NSString *title = [[events objectAtIndex:rowIndex] title];
NSString *strippedNumber = [notes stringByReplacingOccurrencesOfString:#"[^0-9]" withString:#"" options:NSRegularExpressionSearch range:NSMakeRange(0, [notes length])];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSString *date = [dateFormatter stringFromDate:[[events objectAtIndex:rowIndex] startDate]];
if([segueIdentifier isEqualToString:#"IBM"]) {
array = #[notes, title, strippedNumber, date];
}
return array;
}
#end
DetailIntefaceViewController.h:
#import <WatchKit/WatchKit.h>
#import <Foundation/Foundation.h>
#interface DetailInterfaceController : WKInterfaceController
#property (nonatomic, strong) NSString *currentContext;
#property (weak, nonatomic) IBOutlet WKInterfaceLabel *phoneNumber;
#end
DetailIntefaceViewController.m:
#import "DetailInterfaceController.h"
#interface DetailInterfaceController ()
#end
#implementation DetailInterfaceController
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
NSLog(#"%#",context);
self.currentContext = context;
// Configure interface objects here.
}
- (void)willActivate {
// This method is called when watch view controller is about to be visible to user
[super willActivate];
NSLog(#"%# willActivate",self.currentContext);
[self.phoneNumber setText:self.currentContext];
}
- (void)didDeactivate {
// This method is called when watch view controller is no longer visible
[super didDeactivate];
NSLog(#"%# didDeactivate",self.currentContext);
}
#end
Any help would be appreciated.
You don't need that contextsForSegueWithIdentifier method.
After setting up the table, use this method.
- (void)table:(WKInterfaceTable *)table didSelectRowAtIndex:(NSInteger)rowIndex
{
NSString *notes = [[events objectAtIndex:rowIndex] notes];
NSString *title = [[events objectAtIndex:rowIndex] title];
NSString *strippedNumber = [notes stringByReplacingOccurrencesOfString:#"[^0-9]" withString:#"" options:NSRegularExpressionSearch range:NSMakeRange(0, [notes length])];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSString *date = [dateFormatter stringFromDate:[[events objectAtIndex:rowIndex] startDate]];
//You can push controller instead of segue like this and sending the variable data as a dictionary in context,
[self pushControllerWithName:#"NibIdentifier" context:[NSDictionary dictionaryWithObjectsAndKeys:notes,#"notes",title,#"title",strippedNumber,#"strippedNumber",date,#"date",nil]];
}
Replace "NibIdentifier" with your specific identifier from storyboard.
Retrieve the data in another controller from context using this,
- (void)awakeWithContext:(id)context
{
[super awakeWithContext:context];
NSLog(#"%#",[context objectForKey:#"key1"]);
NSLog(#"%#",[context objectForKey:#"key2"]);
NSLog(#"%#",[context objectForKey:#"key3"]);
NSLog(#"%#",[context objectForKey:#"key4"]);
}
Currently I have two NSDateFormatters in my app and I want to somehow "combine" them so I only have, since they're parsing the same date.
I have a NSObject called UpcomingReleases, thats where all my JSON info gets stored.
UpcomingRelease.h
- (NSString *) formattedDate;
UpcomingRelease.m
- (NSString *) formattedDate {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSDate *readableDate = [dateFormatter dateFromString:self.release_date];
[dateFormatter setDateFormat:#"MMMM dd"];
return [dateFormatter stringFromDate:readableDate];
}
My UICollectionViewController (UpcomingReleasesViewController.m)
if([upcomingReleaseDictionary objectForKey:#"release_date"] != NULL)
{
NSString *readableDate = [upcomingReleaseDictionary objectForKey:#"release_date"];
UpcomingRelease *upcoming = [[UpcomingRelease alloc] init];
upcoming.release_date = readableDate;
cell.release_date.text = [NSString stringWithFormat:#"%#", upcoming.formattedDate];
}
My detailedViewController (ReleaseViewController.m)
(_singleRelease is a NSDictionary)
- (void)viewDidLoad
{
[super viewDidLoad];
if([_singleRelease objectForKey:#"release_date"] != NULL)
{
NSString *readableDate = [_singleRelease objectForKey:#"release_date"];
UpcomingRelease *singleRelease = [[UpcomingRelease alloc] init];
singleRelease.release_date = readableDate;
self.release_date.text = [NSString stringWithFormat:#"%#", singleRelease.formattedDate];
}
}
This was working fine, until I added a share on twitter action and I had to add another NSDateFormatter so it could show the readable date inside the tweet (I would get an error saying "No visible interface for ReleaseViewController declares the selected 'formattedDate'" otherwise).
- (NSString *) formattedDate:(NSString *)jsonDateString {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSDate *readableDate = [dateFormatter dateFromString:jsonDateString];
[dateFormatter setDateFormat:#"MMMM dd"];
return [dateFormatter stringFromDate:readableDate];
}
#pragma mark - Share on twitter
- (IBAction)shareOnTwitter:(id)sender {
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter])
{
SLComposeViewController *tweetSheet = [SLComposeViewController
composeViewControllerForServiceType:SLServiceTypeTwitter];
NSString *formattedDate = [self formattedDate:[_singleRelease objectForKey:#"release_date"]];
[tweetSheet setInitialText:[NSString stringWithFormat:#"%#", formattedDate]];
[self presentViewController:tweetSheet animated:YES completion:nil];
}
}
How can I combine both these NSDateFormatters into one? They're both parsing the same string in the same way (also if there's a better way to show the formattedDate string than the one I'm currently doing would be great).
This is how my JSON shows the date string:
release_date: "2013-11-16T00:00:00.000Z"
Thanks.
As #Hot Licks says:
Make the date formatter a class method:
+ (NSString *) formattedDate:(NSString *)jsonDateString {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSDate *readableDate = [dateFormatter dateFromString:jsonDateString];
[dateFormatter setDateFormat:#"MMMM dd"];
return [dateFormatter stringFromDate:readableDate];
}
Put it in a utility class and use it in both cases. In the first case just pass in self.release_date.
I'm changing my app so it could parse my JSON through AFNetworking and I'm getting an error when I try to change my date string with dateFormatter. I have a NSObject called "UpcomingRelease", a CollectionViewController called "UpcomingReleasesViewController" and a destinationViewController called "ReleaseViewController"
This my old code:
* UpcomingRelease.h
#interface UpcomingRelease : NSObject
#property (nonatomic, strong) NSString *release_date;
- (NSString *) formattedDate;
#end
* UpcomingRelease.m
- (NSString *) formattedDate {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSDate *newDate = [dateFormatter dateFromString:self.release_date];
[dateFormatter setDateFormat:#"MMMM dd"];
return [dateFormatter stringFromDate:newDate];
}
* ReleaseViewController.h (destinationViewController)
#import "UpcomingRelease.h"
#property (strong, nonatomic) NSDictionary *singleRelease;
#property (weak, nonatomic) IBOutlet UILabel *release_date;
* ReleaseViewController.m
#synthesize singleRelease = _singleRelease;
#synthesize release_date = _release_date;
- (void)viewDidLoad
{
[super viewDidLoad];
if([_singleRelease objectForKey:#"release_date"] != NULL)
{
self.release_date.text = [NSString stringWithFormat:#"%#", _singleRelease.formattedDate];
}
else
{
self.release_date.text = [NSString stringWithFormat:#"Releasing Soon"];
}
}
I get an error saying "Property 'formattedDate' not found on object of type 'NSDictionary').
The error already says that NSDictionary doesn't have a property called formattedDate. And right now you are calling _singleRelease.formattedDate and _singleRelease is a NSDictionary.
Change your code to the following:
if([_singleRelease objectForKey:#"release_date"] != NULL)
{
NSString *rd = [_singleRelease objectForKey:#"release_date"]; // I assume that this is a string
UpcomingRelease *upcoming = [[UpcomingRelease alloc] init];
upcoming.release_date = rd;
self.release_date.text = [NSString stringWithFormat:#"%#", upcoming.formattedDate];
}
I need to be able to show if the switch is on or off in a alert along with other details, all of the details display just fine but when I try to add the notificationStatus string it gives me an error. "Use of undeclared identifier 'notificationStatus'"
-(void) procrastinationNotificationSwitchOnOrOff {
if (_procrastinationNotificationSwitch.on) {
_notificationOnOffLabel.text = #"Procrastination Notification On";
NSString *notificationStatus = #"NOTIFICATION ON";
NSLog(notificationStatus);
}
else {
_notificationOnOffLabel.text = #"Procrastination Notification Off";
NSString *notificationStatus = #"NOTIFICATION OFF";
NSLog(notificationStatus);
}
}
-(void) presentMessage:(NSString *)message {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Class Stuff" message:message delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
}
-(void) notificationStatus:(NSString *)stat {
NSString *status = [NSString stringWithFormat:#"%#", stat];
}
-(IBAction)returnKeyButton:(id)sender {
[sender resignFirstResponder];
NSString *classNameString = self.className.text;
NSLog(classNameString);
NSString *assignmentTitleString = self.assignmentTitle.text;
NSLog(assignmentTitleString);
NSString *assignmentDescriptionString = self.assignmentDescription.text;
NSLog(assignmentDescriptionString);
NSString *totalStrings = [NSString stringWithFormat:#"%# %# %# %#", classNameString, assignmentTitleString, assignmentDescriptionString, notificationStatus];
NSLog(totalStrings);
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
dateFormatter.timeZone = [NSTimeZone defaultTimeZone];
dateFormatter.timeStyle = NSDateFormatterShortStyle;
dateFormatter.dateStyle = NSDateFormatterShortStyle;
NSString *dateTimeString = [dateFormatter stringFromDate: dateTimePicker.date];
NSLog(#"Alarm Set Button Tapped : %#", dateTimeString );
[self presentMessage:totalStrings];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[_procrastinationNotificationSwitch addTarget:self action:#selector(procrastinationNotificationSwitchOnOrOff) forControlEvents:UIControlEventValueChanged];
}
You have a local variable notificationStatus in your method procrastinationNotificationSwitchOnOrOff. You also have notificationStatus. You don't have a property or instance variable notificationStatus.
Add a property notificationStatus. Get rid of the method notificationStatus. Always read and write notificationStatus using self.notificationStatus. Problem solved.
I think you're confusing things by having the method
-(void) notificationStatus:(NSString *)stat {
NSString *status = [NSString stringWithFormat:#"%#", stat];
}
Would be better off making it a local variable and if you want manipulate it, use getters and setters.
My app is crashing due to an over-released object and I have narrowed it down to the early call of dealloc in a custom class. This causes a crash attributed to an NSMutableArray that is using the custom class listed below:
#import <Foundation/Foundation.h>
#interface GraphData : NSObject{
NSInteger key;
NSString *value;
}
#property (nonatomic, readwrite) NSInteger key;
#property (nonatomic, retain) NSString *value;
-(id)initWithPrimaryKey:(NSInteger) xid;
-(id)initWithName:(NSString *)n key:(NSInteger)i;
#end
#import "GraphData.h"
#implementation GraphData
#synthesize key,value;
-(id)initWithPrimaryKey:(NSInteger) xid{
//[super init];
self=[super init];
if (self){
self.key = xid;
self.value = #"";
}
return self;
}
-(id)initWithName:(NSString *)n key:(NSInteger)i{
self=[super init];
if (self){
self.key = 0;
self.value = n;
}
return self;
}
-(void)dealloc{
NSLog(#"Say bye to %#, kids!", self);
[value release], value = nil;
[super dealloc];
}
#end
Weirdly I'm using GraphData in another class and it works without a problem. In this case however the dealloc calls just before I synthesise the NSMutableArray theNewData property; but after I have synthesised it three times.
-(NSMutableArray*)fillDataInArray:(NSInteger)keyphrase_id{
NSLog(#"lsd");
NSLog(#"Keyphrase_id:%d", keyphrase_id);
NSDate *startdate = [self getDateForApplicationInstalled];
NSDate *enddate = [NSDate date];
NSString *dateString1=[[NSString alloc] initWithString: [fmt stringFromDate:startdate]];
NSString *dateString2=[[NSString alloc] initWithString: [fmt stringFromDate:enddate]];
NSMutableArray *newDataNew = [[NSMutableArray alloc]init];
self.theNewData = newDataNew;
[newDataNew release];
selStmt = nil;
// build select statement
if (!selStmt)
{
const char *sql = "select distinct position, key_time from ranking where keyphrase_id = ? and key_time between ? and ? order by key_time";
if (sqlite3_prepare_v2(database, sql, -1, &selStmt, NULL) != SQLITE_OK)
{
selStmt = nil;
}
NSInteger n = keyphrase_id;
sqlite3_bind_int(selStmt, 1, n);
sqlite3_bind_text(selStmt, 2, [dateString1 UTF8String] , -1, SQLITE_TRANSIENT);
sqlite3_bind_text(selStmt, 3, [dateString2 UTF8String] , -1, SQLITE_TRANSIENT);
NSLog(#"SQL query is: [%s]", sql);
}
if (!selStmt)
{
NSAssert1(0, #"Can't build SQL to read keyphrases [%s]", sqlite3_errmsg(database));
}
int ret;
while ((ret=sqlite3_step(selStmt))==SQLITE_ROW)
{
GraphData *item = [[GraphData alloc]init];
item.key = sqlite3_column_int(selStmt, 0);
item.value = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selStmt,1)];
[self.theNewData addObject:item];
[item release];
}
sqlite3_reset(selStmt); // reset (unbind) statement
[dateString2 release];
[dateString1 release];
return theNewData;
}
It's also accessed in a different method:
-(NSMutableArray *) getDataForCharts:(int)seriesIndex{
NSLog(#"speed");
NSDate *startdate = [self getDateForApplicationInstalled];
NSDate *enddate = [NSDate date];
NSString *dateString1=[[NSString alloc] initWithString: [fmt stringFromDate:startdate]];
NSString *dateString2=[[NSString alloc] initWithString: [fmt stringFromDate:enddate]];
NSMutableArray *newDataNew = [[NSMutableArray alloc]init];
self.actionNoteData = newDataNew;
[newDataNew release];
selStmt = nil;
// build select statement
if (!selStmt)
{
const char *sql = "";
if (seriesIndex == 4) sql = "select distinct 105 score, notes_date from notes where iscompleted =1 and domain_id = ? and notes_date between ? and ? order by notes_date";
if (sqlite3_prepare_v2(database, sql, -1, &selStmt, NULL) != SQLITE_OK)
{
selStmt = nil;
}
NSInteger n = domain_id;
sqlite3_bind_int(selStmt, 1, n);
sqlite3_bind_text(selStmt, 2, [dateString1 UTF8String] , -1, SQLITE_TRANSIENT);
sqlite3_bind_text(selStmt, 3, [dateString2 UTF8String] , -1, SQLITE_TRANSIENT);
NSLog(#"SQL query is: [%s]", sql);
}
if (!selStmt)
{
NSAssert1(0, #"Can't build SQL to read keyphrases [%s]", sqlite3_errmsg(database));
}
// loop reading items from list
int ret;
while ((ret=sqlite3_step(selStmt))==SQLITE_ROW)
{
GraphData *item = [[GraphData alloc]init]; // create item
item.key = sqlite3_column_int(selStmt, 0);
item.value = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selStmt,1)];
NSLog(#"Key:%d", sqlite3_column_int(selStmt, 0));
NSLog(#"Value:%s", sqlite3_column_text(selStmt,1));
[self.actionNoteData addObject:item]; // add to list
[item release]; // free item
}
sqlite3_reset(selStmt); // reset (unbind) statement
[dateString2 release];
[dateString1 release];
return actionNoteData;
}
Zombie points to [i release]; but this is the exact statement called earlier which doesn't result in a crash.
if (index == 4) {
dateComponents.day = ([dateComponents day] -1 ) + dataindex + 1;
if (dataForPlotActionNote.count > dataindex) {
if ([dataForPlotActionNote objectAtIndex:dataindex]) {
GraphData *i = (GraphData *) [dataForPlotActionNote objectAtIndex:dataindex];
NSDate *date = [[[NSDate alloc] init] autorelease];
date =[fmt dateFromString:i.value];
datapoint.xValue = date;//[cal dateFromComponents:dateComponents];
datapoint.yValue = [NSNumber numberWithDouble:(i.key)];
[i release];
}
}
}
What could cause the dealloc call to occur halfway through the executing code?
Could making a GraphData property and reseting it each time help keep it alive long enough?
The [i release] problem makes sense. When you get a reference to the object that's inside dataForPlotActionNote you don't increase its retain count, so you shouldn't be reducing the count either.
The places where you use [item release] are different in that you've created those objects with alloc and therefore do have them retained.