app crashes due to auto adjusting scrollView? - ios

I am having a screen for adding a reminder. The screen is having 2 textfields and 1 textview. These all are under scrollView which is a subclass of TPAvoidingScrollView class. This class itself manages the position of scrollView and hence the components inside as the keyboard appears and disappears.
The screen is as follows.
After I have gone through all the fields and selected certain values. By clicking on Add reminder the event is added into the main calendar and the screen pops out to the previous screen. And then problem starts to occur. As soon as I again comes to this screen and tapping on the Textview Notes the app crashes with these errors.
Here Reminder view controller is the name of the class
The code for the whole class is:
#import "ReminderViewController.h"
#import <EventKit/EventKit.h>
#import "ActionSheetPicker.h"
#import "NSDate-Utilities.h"
#interface ReminderViewController ()
#end
#implementation ReminderViewController
#synthesize scrollView;
#synthesize txt_notes;
#synthesize txt_remindOn;
#synthesize txt_repeatAlarm;
#synthesize btn_appointment;
#synthesize btn_pickup;
#synthesize btn_reminder;
#synthesize txt_currentFocussedTextField;
#synthesize selectedDate;
#synthesize arr_repeatAlarm;
#synthesize selectedIndex;
#synthesize isSelected;
#synthesize str_eventTitle;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.scrollView.contentSize = CGSizeMake(320, 520);
self.selectedDate = [NSDate date];
self.arr_repeatAlarm = [NSArray arrayWithObjects:#"None",#"Every Day", #"Every Week",
#"Every Month", #"Every year", nil];
btn_reminder.backgroundColor =[UIColor colorWithRed:0.0/255 green:89.0/255 blue:178.0/255
alpha:1.0f];
[[AppDelegate sharedInstance] setUpHighlightedStateOfButton:btn_reminder];
// Do any additional setup after loading the view.
}
#pragma mark - Check button click methods
-(IBAction)btn_appointment_click:(id)sender{
if(btn_appointment.selected){
[btn_appointment setSelected:NO];
[btn_pickup setSelected:YES];
isSelected = NO;
}
else{
[btn_appointment setSelected:YES];
[btn_pickup setSelected:NO];
isSelected = YES;
}
}
-(IBAction)btn_pickup_click:(id)sender{
if(btn_pickup.selected){
[btn_pickup setSelected:NO];
[btn_appointment setSelected:YES];
isSelected = NO;
}
else{
[btn_pickup setSelected:YES];
[btn_appointment setSelected:NO];
isSelected = YES;
}
}
#pragma mark - calendar Event methods
- (IBAction)btn_reminder_click:(id)sender{
[self addEventTocalendar:sender];
}
- (void)addEventTocalendar:(id)sender{
EKEventStore *store = [[EKEventStore alloc] init];
[store requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError
*error) {
if (!granted) { return; }
EKEvent *event = [EKEvent eventWithEventStore:store];
event.title = #"Pickup Reminder";
event.startDate = self.selectedDate;
event.endDate = [event.startDate dateByAddingTimeInterval:60*60];//set 1 hour meeting
event.notes = txt_notes.text;
event.recurrenceRules = EKRecurrenceFrequencyDaily;
[event addAlarm:[EKAlarm alarmWithRelativeOffset:60.0f * -5.0f]];
if (selectedIndex == 1) {
[event addRecurrenceRule:[[EKRecurrenceRule
alloc]initRecurrenceWithFrequency:EKRecurrenceFrequencyDaily interval:1 end:Nil]];
}
else if (selectedIndex == 2){
[event addRecurrenceRule:[[EKRecurrenceRule
alloc]initRecurrenceWithFrequency:EKRecurrenceFrequencyWeekly interval:1 end:Nil]];
}
else if (selectedIndex == 3){
[event addRecurrenceRule:[[EKRecurrenceRule
alloc]initRecurrenceWithFrequency:EKRecurrenceFrequencyMonthly interval:1 end:Nil]];
}
else if (selectedIndex == 4){
[event addRecurrenceRule:[[EKRecurrenceRule
alloc]initRecurrenceWithFrequency:EKRecurrenceFrequencyYearly interval:1 end:Nil]];
}
[event setCalendar:[store defaultCalendarForNewEvents]];
NSError *err = nil;
[store saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
NSString *savedEventId = event.eventIdentifier; //this is so you can access this
event later
BOOL isSuceess=[store saveEvent:event span:EKSpanThisEvent error:&err];
// This needs to be done as the UIKIT was getting called from the seconadary thread
and therefore to show the alert view in the main thread and to prevent the hanging of
the app I have to call the Aletview method in the main thread.
// i.e dispatch the event in the main thread
if(isSuceess){
UIAlertView *alertview = [[UIAlertView alloc] initWithTitle:#"Event"
message:#"Event added in calendar" delegate:self cancelButtonTitle:#"OK"
otherButtonTitles:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[alertview show];
});
}
else {
UIAlertView *alertview = [[UIAlertView alloc] initWithTitle:#"Event" message:[err
description] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[alertview show];
});
}
}];
}
- (void)back{
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark - UIAlertViewDelegate methods
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark - Implementation methods
- (void)serviceWasSelected:(NSNumber *)selectedIndex element:(id)element {
self.selectedIndex = [selectedIndex intValue];
//may have originated from textField or barButtonItem, use an IBOutlet instead of element
self.txt_repeatAlarm.text = [self.arr_repeatAlarm objectAtIndex:self.selectedIndex];
}
- (void)dateWasSelected:(NSDate *)selectedDate element:(id)element{ //indexpath:
(NSIndexPath *)indexpath{
UITextField * textfield = (UITextField *)element;
if (textfield == self.txt_remindOn) {
self.selectedDate = selectedDate;
self.txt_remindOn.text = [self.selectedDate getDateStringInFormat:#"dd MMM yyyy
hh:mm aa"];
}
}
#pragma mark - TextField Delegate Methods
- (void)textFieldDidBeginEditing:(UITextField *)textField{
self.txt_currentFocussedTextField = textField;
[[AppDelegate sharedInstance] addToolbarForKeyboard:textField];
if (textField == self.txt_remindOn) {
[textField resignFirstResponder];
_actionSheetPicker = [[ActionSheetDatePicker alloc] initWithTitle:#""
datePickerMode:UIDatePickerModeDateAndTime selectedDate:self.selectedDate
minimumDate:[NSDate
date] maximumDate:Nil target:self action:#selector(dateWasSelected:element:)
origin:textField];
self.actionSheetPicker.hideCancel = NO;
[self.actionSheetPicker showActionSheetPicker];
}
if (textField == self.txt_repeatAlarm) {
[textField resignFirstResponder];
[ActionSheetStringPicker showPickerWithTitle:#"" rows:self.arr_repeatAlarm
initialSelection:self.selectedIndex target:self
successAction:#selector(serviceWasSelected:element:)
cancelAction:#selector(actionPickerCancelled:) origin:textField];
}
}
// making the keyboard disappear on pressing the Done button on the keyboard.
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text {
if([text isEqualToString:#"\n"]) {
[textView resignFirstResponder];
return NO;
}
return YES;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end

Related

How do I add an Event Title (from a UI Text View) to a Calendar Event created by my APP?

I've developed an App and my App needs to create an event at device's calendar. I've been trough EventKitProgGuide and studied the SimpleEKDemo.
By simplifying the code from SimpleEKDemo I generated the code shown below that opens an 'calendar's event screen' straight from my app and generates the event properly. I'm OK with that.
Now I need to use the text content of an UITextView as the Event Title!
Could somebody help my with that code?
Thanks,
Marcos
Here's my code:
#.h
#import <EventKitUI/EventKitUI.h>
#import <EventKit/EventKit.h>
#property (nonatomic, strong) EKEventStore *eventStore;
#property (nonatomic, strong) EKEvent *event;
#property (nonatomic, strong) EKCalendar *defaultCalendar;
#property (nonatomic, strong)
IBOutlet UITextView *textView1;
- (IBAction)agendar:(UIButton *)sender;
#.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.eventStore = [[EKEventStore alloc]init];
self.textView1.text = #"hello world!";
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self checkEventStoreAccessForCalendar];
}
- (IBAction)agendar:(UIButton *)sender {
EKEventEditViewController *addController = [[EKEventEditViewController alloc] init];
addController.eventStore = self.eventStore;
addController.editViewDelegate = self;
[self presentViewController:addController animated:YES completion:nil];
self.event = [EKEvent eventWithEventStore:self.eventStore];
// Jeff's suggested code:
self.event.title = self.textView1.text;
// Jeff's SaveEvent Sugestion
NSError *err;
[self.eventStore saveEvent:self.event span:EKSpanThisEvent error:&err];
}
-(void)checkEventStoreAccessForCalendar
{
EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
switch (status)
{
case EKAuthorizationStatusAuthorized: [self accessGrantedForCalendar];
break;
case EKAuthorizationStatusNotDetermined: [self requestCalendarAccess];
break;
case EKAuthorizationStatusDenied:
case EKAuthorizationStatusRestricted:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alerta de Privacidade" message:#"Permissão de acesso ao calendário não concedida."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
break;
default:
break;
}
}
-(void)requestCalendarAccess
{
[self.eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error)
{
if (granted)
{
Tela8ViewController * weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf accessGrantedForCalendar];
});
}
}];
}
-(void)accessGrantedForCalendar
{
self.defaultCalendar = self.eventStore.defaultCalendarForNewEvents;
}
- (void)eventEditViewController:(EKEventEditViewController *)controller
didCompleteWithAction:(EKEventEditViewAction)action
{
[self dismissViewControllerAnimated:YES completion:^
{
if (action != EKEventEditViewActionCanceled)
{
dispatch_async(dispatch_get_main_queue(), ^{
});
}
}];
}
There are two ways to create an event with EventKit. Your sample code currently has a mix of both, so you should pick just one!
A: Create an event with certain fields pre-set (in your case, the title), and allow the user to review and save it (or choose to cancel and discard it) with EKEventEditViewController. In this case, your code doesn't need to commit the event - just watch for the delegate response to confirm that it happened.
- (void)createEventWithTitle:(NSString *)title
{
EKEvent *newEvent = [EKEvent eventWithEventStore:self.eventStore];
newEvent.title = title;
EKEventEditViewController *controller = [[EKEventEditViewController alloc] init];
controller.eventStore = self.eventStore;
controller.event = newEvent;
controller.editViewDelegate = self;
[self presentViewController:controller animated:YES completion:nil];
}
// EKEventEditViewController delegate method
- (void)eventEditViewController:(EKEventEditViewController *)controller didCompleteWithAction:(EKEventEditViewAction)action
{
if (action == EKEventEditViewActionSaved) {
// event has been committed
}
// alternatives are EKEventEditViewActionCanceled, EKEventEditViewActionDeleted
[self dismissViewControllerAnimated:YES completion:Nil];
}
B. You can create an event and commit it entirely in your code, if you don't need user involvement. In this case you can use EKEventStore saveEvent: span: error: instead of relying on EKEventEditViewController.
Have you tried something like
self.event.title = self.textView1.text;
?

UITABLEView duplicate rows issue

I cannot resolve this issue and I have no idea why my UITableView duplicates rows whenever I click on the segment control. I want to refresh the table view with new data when segment control changes. I have tried many things and googled it but could not find any solution. I would appreciated if someone can help me please. I am still learning xcode and a lot to learn. here is my code -
#import "citsViewController.h"
#import "citsParseOperation.h"
#import "citsFuelFinder.h"
#import "citsTableViewCell.h"
#import "citsAboutViewController.h"
#import "MBProgressHUD.h"
#import <CoreLocation/CoreLocation.h>
// this framework is imported so we can use the kCFURLErrorNotConnectedToInternet error code
#import <CFNetwork/CFNetwork.h>
#import <MapKit/MapKit.h>
#interface citsViewController ()
{
CLLocationManager *locationManager;
CLGeocoder *geocoder;
CLPlacemark *placemark;
NSString *currentLoc;
int productName;
}
#property (nonatomic) NSMutableArray *earthquakeList;
#property (nonatomic) citsFuelFinder *currentEarthquakeObject;
#property (nonatomic, weak) IBOutlet UILabel *locationLabel;
// queue that manages our NSOperation for parsing earthquake data
#property (nonatomic) NSOperationQueue *parseQueue;
#end
#pragma mark -
#implementation citsViewController
#synthesize nomatchesView;
#synthesize footerLabel;
#synthesize headerLabel;
#synthesize fuelType;
#synthesize bannerIsVisible;
- (void)viewDidLoad {
[super viewDidLoad];
//refresh the tableview
UIRefreshControl *refreshControl=[[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(refresh:) forControlEvents:UIControlEventValueChanged];
self.refreshControl=refreshControl;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
[infoButton addTarget:self action:#selector(aboutUs:) forControlEvents:UIControlEventTouchUpInside];
//add info button in the navigation controller
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:infoButton] ;
//initialize location manager
locationManager=[[CLLocationManager alloc] init];
//to get location
geocoder=[[CLGeocoder alloc] init];
//show network activity
[UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE;
locationManager.delegate=self;
locationManager.desiredAccuracy=kCLLocationAccuracyBest;
//call the location manager update function
[locationManager startUpdatingLocation];
}
-(void)refresh:(id)sender {
//update table data
[locationManager startUpdatingLocation];
[self.refreshControl endRefreshing];
[self.tableView reloadData];
}
- (void)dealloc {
// we are no longer interested in these notifications:
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kAddEarthquakesNotificationName
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kEarthquakesErrorNotificationName
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSCurrentLocaleDidChangeNotification
object:nil];
}
/**
Handle errors in the download by showing an alert to the user. This is a very simple way of handling the error, partly because this application does not have any offline functionality for the user. Most real applications should handle the error in a less obtrusive way and provide offline functionality to the user.
*/
- (void)handleError:(NSError *)error {
NSString *errorMessage = [error localizedDescription];
NSString *alertTitle = NSLocalizedString(#"Error", #"Title for alert displayed when download or parse error occurs.");
NSString *okTitle = NSLocalizedString(#"OK ", #"OK Title for alert displayed when download or parse error occurs.");
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:alertTitle message:errorMessage delegate:nil cancelButtonTitle:okTitle otherButtonTitles:nil];
[alertView show];
}
/**
Our NSNotification callback from the running NSOperation to add the earthquakes
*/
- (void)addEarthquakes:(NSNotification *)notif {
assert([NSThread isMainThread]);
[self addEarthquakesToList:[[notif userInfo] valueForKey:kEarthquakeResultsKey]];
}
/**
Our NSNotification callback from the running NSOperation when a parsing error has occurred
*/
- (void)earthquakesError:(NSNotification *)notif {
assert([NSThread isMainThread]);
[self handleError:[[notif userInfo] valueForKey:kEarthquakesMessageErrorKey]];
}
/**
The NSOperation "ParseOperation" calls addEarthquakes: via NSNotification, on the main thread which in turn calls this method, with batches of parsed objects. The batch size is set via the kSizeOfFuelPumpBatch constant.
*/
- (void)addEarthquakesToList:(NSArray *)earthquakes {
NSInteger startingRow = [self.earthquakeList count];
NSInteger earthquakeCount = [earthquakes count];
NSMutableArray *indexPaths = [[NSMutableArray alloc] initWithCapacity:earthquakeCount];
for (NSInteger row = startingRow; row < (startingRow+earthquakeCount); row++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
[indexPaths addObject:indexPath];
}
NSLog(#"record count %d",earthquakeCount);
[self.earthquakeList addObjectsFromArray:earthquakes];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
//[self.tableView reloadData];
}
#pragma mark - UITableViewDelegate
// The number of rows is equal to the number of earthquakes in the array.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.earthquakeList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kEarthquakeCellID = #"EarthquakeCellID";
citsTableViewCell *cell = (citsTableViewCell *)[tableView dequeueReusableCellWithIdentifier:kEarthquakeCellID];
if(cell==nil)
{
cell=[[citsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kEarthquakeCellID];
}
// Get the specific earthquake for this row.
citsFuelFinder *earthquake = (self.earthquakeList)[indexPath.row];
[cell configureWithEarthquake:earthquake];
return cell;
}
/**
* When the user taps a row in the table, display the USGS web page that displays details of the earthquake they selected.
*/
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *buttonTitle = NSLocalizedString(#"Cancel", #"Cancel");
//NSString *buttonTitle1 = NSLocalizedString(#"Show USGS Site in Safari", #"Show USGS Site in Safari");
NSString *buttonTitle2 = NSLocalizedString(#"Show Location in Maps", #"Show Location in Maps");
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self
cancelButtonTitle:buttonTitle destructiveButtonTitle:nil
otherButtonTitles: buttonTitle2, nil];
[sheet showInView:self.view];
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.bounds.size.width, 500)];
headerLabel=[[UILabel alloc] initWithFrame:CGRectMake(10, 1.0, 300, 25)];
headerLabel.numberOfLines=0;
fuelType=[[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"ULP", #"PULP",#"Diesel",#"LPG", nil]];
fuelType.frame = CGRectMake(10, 30, 300,25);
//set first segment selected
[fuelType setSelectedSegmentIndex:0];
[fuelType addTarget:self action:#selector(segmentedControlHasChangedValue) forControlEvents:UIControlEventValueChanged];
headerLabel.font=[UIFont systemFontOfSize:10.0];
[headerView insertSubview:fuelType aboveSubview:headerLabel];
[headerView addSubview:headerLabel];
[headerView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"footer.gif"]]];
return headerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 60;
}
#pragma mark -
/**
* Called when the user selects an option in the sheet. The sheet will automatically be dismissed.
*/
- (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex {
NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
citsFuelFinder *earthquake = (citsFuelFinder *)(self.earthquakeList)[selectedIndexPath.row];
switch (buttonIndex) {
case 0: {
// open the earthquake info in Maps
// create a map region pointing to the earthquake location
CLLocationCoordinate2D location = (CLLocationCoordinate2D) { earthquake.latitude, earthquake.longitude };
NSValue *locationValue = [NSValue valueWithMKCoordinate:location];
MKCoordinateSpan span = (MKCoordinateSpan) { 2.0, 2.0 };
NSValue *spanValue = [NSValue valueWithMKCoordinateSpan:span];
NSDictionary *launchOptions = #{ MKLaunchOptionsMapTypeKey : #(MKMapTypeStandard),
MKLaunchOptionsMapCenterKey : locationValue,
MKLaunchOptionsMapSpanKey : spanValue,
MKLaunchOptionsShowsTrafficKey : #(NO),
MKLaunchOptionsDirectionsModeDriving : #(NO) };
// make sure the map item has a pin placed on it with the title as the earthquake location
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:location addressDictionary:nil];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:earthquake.location];
[mapItem openInMapsWithLaunchOptions:launchOptions];
break;
}
}
[self.tableView deselectRowAtIndexPath:selectedIndexPath animated:YES];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
// Regiser for HUD callbacks so we can remove it from the window at the right time
HUD.delegate = self;
HUD.labelText = #"Loading";
HUD.detailsLabelText = #"updating data";
HUD.square = YES;
self.earthquakeList = [NSMutableArray array];
self.currentEarthquakeObject=nil;
if([self.earthquakeList count] >0)
{
[self.earthquakeList removeAllObjects];
[self.tableView reloadData];
}
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(addEarthquakesToList:) onTarget:self withObject:nil animated:YES];
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
NSString *latitude=[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
NSString *longitude=[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
citsTableViewCell *tcell = [[citsTableViewCell alloc] init];
//set the latitude and longitude
tcell.lon =[longitude doubleValue];
tcell.lat = [latitude doubleValue];
NSLog(#"Lat:%#, Lon:%#", latitude,latitude);
}
//stop updating location
[locationManager stopUpdatingLocation];
//reverse geocoding
NSLog(#"Resolving the address");
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
currentLoc=[NSString stringWithFormat:#"%#",placemark.locality];
if(currentLoc == NULL)
{
currentLoc=#"N/A";
}
NSLog(#"%#",currentLoc);
//add text to headertext
NSDate *currDate=[NSDate date];
NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/yy HH:mm:ss"];
NSString *dateString=[dateFormatter stringFromDate:currDate];
NSString *loc=[NSString stringWithFormat:#"Your location: %#, Updated on: %#", currentLoc, dateString ];
[dateFormatter setDateFormat:#"EEEE, dd/MM/yyyy"];
NSString *headerDate=[dateFormatter stringFromDate:currDate];
headerLabel.text=[NSString stringWithFormat:#"Prices for: %#\n%#", headerDate,loc];
//currentLoc=[NSString stringWithFormat:#"%#", placemark.locality];
currentLoc=#"Mirrabooka";
if(productName==0)
{
productName=1;
}
NSString *prdStr=[[NSString alloc] initWithFormat:#"%d", productName];
NSString *str =[currentLoc stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
NSString *feedURLString =[[NSString alloc] initWithFormat: #"http://www.fuelwatch.wa.gov.au/fuelwatch/fuelWatchRSS?Product=%#&Suburb=%#", prdStr,str ];
NSURLRequest *earthquakeURLRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:feedURLString]];
NSLog(#"%#",feedURLString);
// send the async request (note that the completion block will be called on the main thread)
//
// note: using the block-based "sendAsynchronousRequest" is preferred, and useful for
// small data transfers that are likely to succeed. If you doing large data transfers,
// consider using the NSURLConnectionDelegate-based APIs.
//
[NSURLConnection sendAsynchronousRequest:earthquakeURLRequest queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// back on the main thread, check for errors, if no errors start the parsing
//
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
// here we check for any returned NSError from the server, "and" we also check for any http response errors
if (error != nil) {
[self handleError:error];
}
else {
// check for any response errors
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if ((([httpResponse statusCode]/100) == 2) ) {
// Update the UI and start parsing the data,
// Spawn an NSOperation to parse the earthquake data so that the UI is not
// blocked while the application parses the XML data.
//
citsParseOperation *parseOperation = [[citsParseOperation alloc] initWithData:data];
[self.parseQueue addOperation:parseOperation];
}
else {
NSString *errorString =
NSLocalizedString(#"HTTP Error", #"Error message displayed when receving a connection error.");
NSDictionary *userInfo = #{NSLocalizedDescriptionKey : errorString};
NSError *reportError = [NSError errorWithDomain:#"HTTP"
code:[httpResponse statusCode]
userInfo:userInfo];
[self handleError:reportError];
}
}
}];
// Start the status bar network activity indicator.
// We'll turn it off when the connection finishes or experiences an error.
//
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
self.parseQueue = [NSOperationQueue new];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(addEarthquakes:)
name:kAddEarthquakesNotificationName object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(earthquakesError:)
name:kEarthquakesErrorNotificationName object:nil];
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
NSLog(#"%d",[self.earthquakeList count]);
}
-(void)clearData{
[self.tableView beginUpdates];
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (int i = [self.tableView numberOfRowsInSection:0] - 1; i >= 0; i--)
{
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:0]];
NSLog(#"Deleted: %d",i);
}
[self.tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationFade];
[self.earthquakeList removeAllObjects];
[self.tableView endUpdates];
//[self.tableView reloadData] ;
}
-(void)segmentedControlHasChangedValue{
int product;
product=fuelType.selectedSegmentIndex;
switch (product) {
case 0:
productName=1;
[locationManager startUpdatingLocation];
[self clearData];
break;
case 1:
productName=2;
[self clearData];
[locationManager startUpdatingLocation];
break;
case 2:
productName=4;
[self clearData];
[locationManager startUpdatingLocation];
break;
case 3:
prod![enter image description here][1]uctName=5;
[self clearData];
[locationManager startUpdatingLocation];
break;
}
NSLog(#"%d",productName);
return;
}
#end
Try removing all previous object from the self.earthquakeList before adding new 1. use [self.earthquakeList removeAllObjects]
Remove this Line,
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
And uncomment,
[self.tableView reloadData];
You are Already updating the data set, So you just need to reload the tableView instead of explicitly insert row.

Clean array by using delegate

I made an AR app that recognize image and show the object recognized in an AlertView. In the AlertView I have 2 buttons: Add and Cancel, I'm using the UIAlertViewDelegate to understand which button the user pressed. If the user press the Add button, the object recognized will be stored in an array. I pass this array to another ViewController, in which I set up a TableView. On the bottom of this TableView there's a button "Pay" to go to another ViewController in which I display the total price of the object recognized. From the last ViewController I can press a button to pay the objects I selected by using the AR. Now when I press this button the app close this ViewController and go back to the first ViewController, but the array in which I stored the object that the AR recognized it's full. To delete the content of this array I thought that the best way is to use the delegation methods, so I made this:
PaymentViewController.h
#import <UIKit/UIKit.h>
#protocol PaymentViewControllerDelegate;
#interface PaymentViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *labelTotal;
- (IBAction)buttonClosePaymentVC:(id)sender;
- (IBAction)buttonPay:(id)sender;
#property(nonatomic,strong)NSString *total;
#property(assign) id<PaymentViewControllerDelegate> delegate;
#end
#protocol PaymentViewControllerDelegate <NSObject>
- (void)cleanReportArray;
#end
PaymentViewController.m
#import "PaymentViewController.h"
#interface PaymentViewController () <UIAlertViewDelegate>
#end
#implementation PaymentViewController
#synthesize delegate = _delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.labelTotal.text = self.total;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)buttonClosePaymentVC:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)buttonPay:(id)sender {
NSString *pay = [NSString stringWithFormat:#"Stai per pagare %#, procedi?", self.total];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"HelloMS" message:pay delegate:self cancelButtonTitle:#"Si" otherButtonTitles:#"No", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
// Procedura per il pagamento e cancellazione del file plist
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"objects.plist"];
NSError *error;
if (![[NSFileManager defaultManager]removeItemAtPath:path error:&error]) {
NSLog(#"Errore: %#", error);
}
__weak UIViewController *vcThatPresentedCurrent = self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^{
[vcThatPresentedCurrent dismissViewControllerAnimated:YES completion:nil];
}];
[self.delegate cleanReportArray];
}
if (buttonIndex == 1) {
// Non deve far nulla: fa scomparire l'UIAlertView
}
}
Here I post to you the method of the class that will use the delegate:
Interface of the ScannerViewController.m
#interface ScannerViewController () <MSScannerSessionDelegate, PaymentViewControllerDelegate, UIActionSheetDelegate, UIAlertViewDelegate>
#property (weak) IBOutlet UIView *videoPreview;
- (IBAction)stopScanner:(id)sender;
#end
In ViewDidLoad I inserted this rows:
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
And in the ScannerViewController.m I implemented the method I declared in PaymentViewController.h:
- (void)cleanReportArray {
[arrayObjectAdded removeAllObjects];
}
I tested my app on my iPhone, the app works fine until I try to pay the objects I scanned by camera, indeed, I tried to pay the object, but it doesn't clean the array in which I stored the objects scanned.
What's wrong in my code? I used an tutorial on the web to understand better how the delegation method works. I hope you can help me to fix this issue, thank you
UPDATE:
here i will post my ScannerViewController code:
ScannerViewController.h
#import <UIKit/UIKit.h>
#interface ScannerViewController : UIViewController
#end
ScannerViewController.m
#import "ScannerViewController.h"
#import "PaymentViewController.h"
#import "ReportViewController.h"
#import "MSScannerSession.h"
#import "MSResult.h"
#import "XmlReader.h"
static int kMSScanOptions = MS_RESULT_TYPE_IMAGE |
MS_RESULT_TYPE_EAN8 |
MS_RESULT_TYPE_EAN13;
#interface ScannerViewController () <MSScannerSessionDelegate, PaymentViewControllerDelegate, UIActionSheetDelegate, UIAlertViewDelegate>
#property (weak) IBOutlet UIView *videoPreview;
- (IBAction)stopScanner:(id)sender;
#end
#implementation ScannerViewController {
MSScannerSession *_scannerSession;
NSString *nameOfObjectScanned;
XmlReader *reader;
NSMutableArray *arrayObjectAdded;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_scannerSession = [[MSScannerSession alloc] initWithScanner:[MSScanner sharedInstance]];
[_scannerSession setScanOptions:kMSScanOptions];
[_scannerSession setDelegate:self];
}
return self;
}
- (void)session:(MSScannerSession *)scanner didScan:(MSResult *)result {
if (!result) {
return;
}
[_scannerSession pause];
NSString *resultStr = nil;
if (result) {
switch ([result getType]) {
case MS_RESULT_TYPE_IMAGE:
resultStr = [NSString stringWithFormat:#"Immagine trovata: %#", [result getValue]];
break;
case MS_RESULT_TYPE_EAN8:
case MS_RESULT_TYPE_EAN13:
resultStr = [NSString stringWithFormat:#"EAN trovato: %#", [result getValue]];
break;
default:
break;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
UIActionSheet *asView = [[UIActionSheet alloc]initWithTitle:resultStr delegate:self cancelButtonTitle:#"OK" destructiveButtonTitle:nil otherButtonTitles:nil, nil];
asView.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
[asView showInView:self.view];
[self addObjectToList:resultStr];
});
}
- (void)addObjectToList:(NSString *)objectName {
// Ricerca dell'oggetto
NSString *object = [objectName substringFromIndex:18];
if ([object isEqualToString:#"Binario_con_coppia"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Dadi_colorati"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Dadi_rossi"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Bici_da_corsa"]) {
[self showAlert:object];
}
}
- (void)showAlert:(NSString*)name {
name = [name stringByReplacingOccurrencesOfString:#"_" withString:#" "];
nameOfObjectScanned = name;
NSString *message = [NSString stringWithFormat:#"Ho riconosciuto questo oggetto: %#, vuoi aggiungerlo al carrello?", name];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"HelloMS" message:message delegate:self cancelButtonTitle:#"Aggiungi" otherButtonTitles:#"Annulla", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
NSLog(#"Aggiungi");
for (int i = 0; i < [reader.objArray count]; i++) {
if ([[reader.objArray[i]objectForKey:#"name"] isEqualToString:nameOfObjectScanned]) {
// Salvo il nome dell'oggetto trovato, il prezzo e la descrizione
NSString *name = [reader.objArray[i]objectForKey:#"name"];
NSString *desc = [reader.objArray[i]objectForKey:#"desc"];
NSString *price = [reader.objArray[i]objectForKey:#"price"];
NSDictionary *newObjectAdded = [[NSDictionary alloc]init];
newObjectAdded = #{#"name": name,
#"desc": desc,
#"price": price};
[arrayObjectAdded addObject:newObjectAdded];
}
}
} else {
NSLog(#"Annulla");
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
[_scannerSession resume];
}
- (void)viewDidLoad
{
[super viewDidLoad];
arrayObjectAdded = [[NSMutableArray alloc]init];
CALayer *videoPreviewLayer = [self.videoPreview layer];
[videoPreviewLayer setMasksToBounds:YES];
CALayer *captureLayer = [_scannerSession previewLayer];
[captureLayer setFrame:[self.videoPreview bounds]];
[videoPreviewLayer insertSublayer:captureLayer below:[[videoPreviewLayer sublayers] objectAtIndex:0]];
reader = [[XmlReader alloc]init];
[reader parseXml];
[_scannerSession startCapture];
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
}
- (void)cleanReportArray {
[arrayObjectAdded removeAllObjects];
}
- (void)dealloc {
[_scannerSession stopCapture];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)stopScanner:(id)sender {
ReportViewController *reportVC = [[ReportViewController alloc]initWithNibName:#"ReportViewController" bundle:nil];
reportVC.reportArray = arrayObjectAdded;
[reportVC setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentViewController:reportVC animated:YES completion:nil];
}
#end
To recognize picture I'm using this AR SDK. I hope you can help me to understand where's my issue
Your problem is that in viewDidLoad you have the code:
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
this is the last thing you do in that method. So the instance of PaymentViewController that you create and set the delegate on is immediately destroyed (by ARC).
You need to modify your code so that you call setDelegate: on the actual instance of PaymentViewController that is presented on screen as this is the instance that needs to use the delegate (it receives the callback from the alert view).

validation method doesn't gets called and segue doesn't gets triggered

I am trying to implement a sign up process with a parse backend. I have a validation method called processFieldEntries and once the done button gets enabled, I try to trigger the segue that I setup modally from my view controller(not from the done button) from view did appear method but neither the validation method gets called nor the segue gets triggered. I setup some debug and logging breakpoints for debugging but, I couldn't go any further apart from the fact that it does not see the view did load. I also tried setting up the segue from the done button. When I did that, the segue gets triggered, not from the code but from storyboard my storyboard here. If someone can help me to figure out how to call processfieldentriees along with the segue, I would really appreciate. Thank you.
NewUserSignUpViewController.h
#import <UIKit/UIKit.h>
#import "ProfileViewController.h"
#interface NewUserSignUpViewController : UIViewController<UITextFieldDelegate>
#property (strong, nonatomic) IBOutlet UIBarButtonItem *barButtonItem;
#property (strong, nonatomic) IBOutlet UITextField *usernameField;
#property (strong, nonatomic) IBOutlet UITextField *passwordField;
#property (strong, nonatomic) IBOutlet UITextField *repeatPasswordField;
- (IBAction)doneEvent:(id)sender;
- (IBAction)cancelEvent:(id)sender;
#end
NewUserSignUpViewController.m
#import "NewUserSignUpViewController.h"
#import "ProfileViewController.h"
#import <Parse/Parse.h>
#import "ActivityView.h"
#interface NewUserSignUpViewController ()
-(void)processFieldEntries;
- (void)textInputChanged:(NSNotification *)note;
- (BOOL)shouldEnableDoneButton;
#end
#implementation NewUserSignUpViewController
#synthesize barButtonItem = _doneButtonInTheBar;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(textInputChanged:) name:UITextFieldTextDidChangeNotification object:_usernameField];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(textInputChanged:) name:UITextFieldTextDidChangeNotification object:_passwordField];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(textInputChanged:) name:UITextFieldTextDidChangeNotification object:_repeatPasswordField];
}
-(void)viewDidAppear:(BOOL)animated
{
[_usernameField becomeFirstResponder];
[super viewDidAppear:animated];
//perform the segue
if (_doneButtonInTheBar.enabled == YES) {
[self performSegueWithIdentifier:#"segueToProfileView" sender:self];
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)dealloc {
}
#pragma mark - UITextFieldDelegate
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{ textField.delegate = self;
if (textField == _usernameField) {[_usernameField becomeFirstResponder];}
if (textField == _passwordField){[_passwordField becomeFirstResponder];}
if (textField == _repeatPasswordField)
{
[_repeatPasswordField becomeFirstResponder];
[self processFieldEntries];
}
return YES;
}
-(BOOL)shouldEnableDoneButton
{
BOOL enableDoneButton = NO;
if (_usernameField.text != nil && _usernameField.text.length != 0 &&_passwordField.text != nil &&
_passwordField.text.length !=0 && _repeatPasswordField.text != nil &&
_repeatPasswordField.text.length != 0) {
enableDoneButton = YES;
[self processFieldEntries];
}
return enableDoneButton;
}
-(void)textInputChanged:(NSNotification *)note
{
_doneButtonInTheBar.enabled = [ self shouldEnableDoneButton];
}
- (IBAction)doneEvent:(id)sender {
[_usernameField resignFirstResponder];
[_passwordField resignFirstResponder];
[_repeatPasswordField resignFirstResponder];
NSLog(#"processfieldentries");
[self processFieldEntries];
}
- (IBAction)cancelEvent:(id)sender {
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)processFieldEntries
{
// Check that we have a non-zero username and passwords.
// Compare password and passwordAgain for equality
// Throw up a dialog that tells them what they did wrong if they did it wrong.
NSString *username = _usernameField.text;
NSString *password = _passwordField.text;
NSString *passwordAgain = _repeatPasswordField.text;
NSString *errorText = #"Please ";
NSString *usernameBlankText = #"enter a username";
NSString *passwordBlankText = #"enter a password";
NSString *joinText = #", and ";
NSString *passwordMismatchText = #"enter the same password twice";
BOOL textError = NO;
// Messaging nil will return 0, so these checks implicitly check for nil text.
if (username.length == 0 || password.length == 0 || passwordAgain.length == 0) {
textError = YES;
//setting the keyboard for th first missing output
if (passwordAgain.length == 0) {
[_repeatPasswordField becomeFirstResponder];
}
if (password.length == 0) {
[_passwordField becomeFirstResponder];
}
if (username.length == 0) {
[_usernameField becomeFirstResponder];
}
if (username.length == 0) {
errorText = [errorText stringByAppendingString:usernameBlankText];
}
if (password.length == 0 || passwordAgain.length == 0) {
if (username.length == 0) { // We need some joining text in the error:
errorText = [errorText stringByAppendingString:joinText];
}
errorText = [errorText stringByAppendingString:passwordBlankText];
}
}else if ([password compare:passwordAgain] != NSOrderedSame)
{errorText = [errorText stringByAppendingString:passwordMismatchText];
[_passwordField becomeFirstResponder];}
if (textError) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:errorText message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alertView show];
return;
// Everything looks good; try to log in.
// Disable the done button for now.
_doneButtonInTheBar.enabled = NO;
ActivityView *activityView = [[ActivityView alloc]initWithFrame:CGRectMake(0.f, 0.f, self.view.frame.size.width, self.view.frame.size.height)];
UILabel *label = activityView.label;
label.text = #"signing up";
label.font = [UIFont boldSystemFontOfSize:20.0f];
[activityView.activityIndicator startAnimating];
[activityView layoutSubviews];
[self.view addSubview:activityView];
// Call into an object somewhere that has code for setting up a user.
// The app delegate cares about this, but so do a lot of other objects.
// For now, do this inline.
NSLog(#"does it reach here");
PFUser *user = [PFUser user];
user.username = username;
user.password = password;
[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[[error userInfo] objectForKey:#"error"] message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alertView show];
_doneButtonInTheBar.enabled = [self shouldEnableDoneButton];
[activityView.activityIndicator stopAnimating];
[activityView removeFromSuperview];
// Bring the keyboard back up, because they'll probably need to change something.
[_usernameField becomeFirstResponder];
return;
}
// Success!
[activityView.activityIndicator stopAnimating];
[activityView removeFromSuperview];
}];
}
}
#end
You could try not to use performSegueWithIdentifier inside viewDidAppear (performSegue actually take you to the other ViewController). Instead you could call it from an IBAction method connected to the done button, after calling in the same method processFieldEntries. I hope this can help you :)

Code does not wait for user to finish typing in the repeat password section

I am trying to setup a signup view with using parse.com as backend but for some reason whenever i start typing in the reenter password field, as soon as i type something, it starts going through this
else if ([password compare:passwordAgain] != NSOrderedSame) {
// We have non-zero strings.
// Check for equal password strings.
textError = YES;
errorText = [errorText stringByAppendingString:passwordMismatchText];
[_reEnterPasswordField becomeFirstResponder];
NSLog(#"stops here");
}
method and sends me the error message passwordMismatchText. It goes through this message everytime i change a word whether i added or deleted it. When I use the same methods with xib the files i had no problem. But after I try to do the same thing with storyboards I am having this issue. I tried creating a user default for _doneButton.enabled == YES and put an another if around the errorText =[...] message, but did not solve the problem. I appreciate for the help.
SignUpViewController.h
#import <UIKit/UIKit.h>
#interface SignUpViewController : UIViewController<UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UIBarButtonItem *doneButton;
#property (weak, nonatomic) IBOutlet UITextField *userNameField;
#property (weak, nonatomic) IBOutlet UITextField *passwordField;
#property (weak, nonatomic) IBOutlet UITextField *reEnterPasswordField;
- (IBAction)done:(id)sender;
- (IBAction)cancel:(id)sender;
#end
SignUpViewController.m
#import "SignUpViewController.h"
#import <Parse/Parse.h>
#import "ActivityView.h"
#import "ProfileViewController.h"
#interface SignUpViewController ()
- (void)textInputChanged:(NSNotification *)note;
-(void)processFieldEntries;
- (BOOL)shouldEnableDoneButton;
#end
#implementation SignUpViewController
#synthesize doneButton = _doneButton;
#synthesize userNameField = _userNameField;
#synthesize passwordField = _passwordField;
#synthesize reEnterPasswordField = _reEnterPasswordField;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter ]addObserver:self selector:#selector(textInputChanged:) name: UITextFieldTextDidChangeNotification object:_userNameField];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(textInputChanged:) name:UITextFieldTextDidChangeNotification object:_passwordField];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(textInputChanged:) name:UITextFieldTextDidChangeNotification object:_reEnterPasswordField];
_doneButton.enabled = NO;
NSLog(#"nsnotification is working fine");
}
-(void)viewWillAppear:(BOOL)animated
{
[_userNameField becomeFirstResponder];
[super viewWillAppear:animated];
NSLog(#"indeed usernamefield became a first responder");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == _userNameField ) {
[_userNameField becomeFirstResponder];
}
if (textField == _passwordField) {
[_passwordField becomeFirstResponder];
}
if (textField == _reEnterPasswordField)
{
[_reEnterPasswordField becomeFirstResponder];
}
NSLog(#"keyboard action works fine ");
return YES;
}
-(BOOL)shouldEnableDoneButton
{
BOOL enableDoneButton = NO;
if (_userNameField.text != nil &&
_userNameField.text.length > 0 &&
_passwordField.text != nil &&
_passwordField.text.length > 0 &&
_reEnterPasswordField.text != nil &&
_reEnterPasswordField.text.length > 0)
{
[self processFieldEntries];
enableDoneButton = YES;
NSLog(#"done button enabled");
}
return enableDoneButton;
}
-(void)textInputChanged:(NSNotification *)note
{
_doneButton.enabled = [self shouldEnableDoneButton];
}
- (IBAction)done:(id)sender {
[_userNameField resignFirstResponder];
[_passwordField resignFirstResponder];
[_reEnterPasswordField resignFirstResponder];
[self processFieldEntries];
NSLog(#"do you see this");
}
- (IBAction)cancel:(id)sender
{
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
-(void)processFieldEntries
{
// Check that we have a non-zero username and passwords.
// Compare password and passwordAgain for equality
// Throw up a dialog that tells them what they did wrong if they did it wrong.
NSString *username = _userNameField.text;
NSString *password = _passwordField.text;
NSString *passwordAgain = _reEnterPasswordField.text;
NSString *errorText = #"Please ";
NSString *usernameBlankText = #"enter a username";
NSString *passwordBlankText = #"enter a password";
NSString *joinText = #", and ";
NSString *passwordMismatchText = #"enter the same password twice";
BOOL textError = NO;
NSLog(#"validation begins here");
// Messaging nil will return 0, so these checks implicitly check for nil text.
if (username.length == 0 || password.length == 0 || passwordAgain.length == 0) {
textError = YES;
// Set up the keyboard for the first field missing input:
if (passwordAgain.length == 0) {
[_reEnterPasswordField becomeFirstResponder];
}
if (password.length == 0) {
[_passwordField becomeFirstResponder];
}
if (username.length == 0) {
[_userNameField becomeFirstResponder];
}
if (username.length == 0) {
errorText = [errorText stringByAppendingString:usernameBlankText];
}
if (password.length == 0 || passwordAgain.length == 0) {
if (username.length == 0) { // We need some joining text in the error:
errorText = [errorText stringByAppendingString:joinText];
}
errorText = [errorText stringByAppendingString:passwordBlankText];
}
} else if ([password compare:passwordAgain] != NSOrderedSame) {
// We have non-zero strings.
// Check for equal password strings.
textError = YES;
errorText = [errorText stringByAppendingString:passwordMismatchText];
[_reEnterPasswordField becomeFirstResponder];
NSLog(#"stops here");
}
if (textError) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:errorText message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alertView show];
return;
}
NSLog(#"validation works just fine");
// Everything looks good; try to log in.
// Disable the done button for now.
_doneButton.enabled = NO;
ActivityView *activityCircle = [[ActivityView alloc] initWithFrame:CGRectMake(0.f, 0.f, self.view.frame.size.width, self.view.frame.size.height)];
UILabel *label = activityCircle.label;
label.text = #"Signing You Up";
label.font = [UIFont boldSystemFontOfSize:20.f];
[activityCircle.activityIndicator startAnimating];
[activityCircle layoutSubviews];
[self.view addSubview:activityCircle];
NSLog(#"activity view works just fine");
//parse registeration
// Call into an object somewhere that has code for setting up a user.
// The app delegate cares about this, but so do a lot of other objects.
// For now, do this inline.
PFUser *user = [PFUser user];
user.username = username;
user.password = password;
[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[[error userInfo] objectForKey:#"error"] message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alertView show];
_doneButton.enabled = [self shouldEnableDoneButton];
[activityCircle.activityIndicator stopAnimating];
[activityCircle removeFromSuperview];
// Bring the keyboard back up, because they'll probably need to change something.
[_userNameField becomeFirstResponder];
return;
}
// Success!
[activityCircle.activityIndicator stopAnimating];
[activityCircle removeFromSuperview];
//add the next screen here
}];
NSLog(#"user signedup just fine");
//now pass the view from sign up to profile view
}
/*
//this one didnt work
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
ProfileViewController *myProfileView = [segue destinationViewController];
if (_doneButton.enabled == YES) {
[myProfileView performSegueWithIdentifier:#"SignUpSegue" sender:_doneButton];
}
}
*/
-(BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
NSLog(#"is this method visible");
if (_doneButton.enabled == YES) {
[self performSegueWithIdentifier:#"SignUpSegue" sender:_doneButton];
}
return NO;
}
#end
this is the log files that I am getting
2013-09-06 02:49:19.938 nsnotification is working fine
2013-09-06 02:49:19.942 indeed usernamefield became a first responder
2013-09-06 02:49:47.446 validation begins here
2013-09-06 02:49:47.448 stops here
2013-09-06 02:49:47.485 done button enabled
2013-09-06 02:49:49.271 validation begins here
2013-09-06 02:49:49.273 stops here
2013-09-06 02:49:49.296 done button enabled
2013-09-06 02:49:51.257 validation begins here
2013-09-06 02:49:51.259 validation works just fine
2013-09-06 02:49:51.265 activity view works just fine
2013-09-06 02:49:51.270 user signedup just fine
2013-09-06 02:49:51.271 done button enabled
You are triggering the code to run by your observation of UITextFieldTextDidChangeNotification. As this moves through your methods you eventually call processFieldEntries. Probably you shouldn't be calling processFieldEntries from shouldEnableDoneButton.

Resources