My Gold Challenge Solution


#1

Took a few hours and a late night to figure this one out. The main issue I was having was getting the date picker to show the date of the item from the detail view.

First I modified the BNRItem class to change the date of an item…

Here is the code…

I added a method to BNRItem.h to change the date:

-(void)changeDate:(NSDate *)dateCreated;

I them implemented the method in BNRItem.m:

-(void)changeDate:(NSDate *)dateCreated
{
    _dateCreated = dateCreated;
}

I then created a new view controller for the date picker and added the date picker to the view programmatically. I didn’t use the .xib file because I wanted practice adding things to the view programmatically because I have read this is a preferred technique in the iOS developer world…

I added 2 properties to this class: a BNRItem and a UIDatePicker
BNRChangeDateViewController.h

#import <UIKit/UIKit.h>
@class BNRItem;

@interface BNRChangeDateViewController : UIViewController

@property (nonatomic, strong) BNRItem *item;
@property (strong, nonatomic) UIDatePicker *datePicker;

@end

In BNRChangeDateViewController.m I added my code to viewDidLoad:. I initialized the date picker and set its frame. I set the mode of the date picker to show the date only. I then set the date of the date picker to the date of the item from the detail view’s. Then I created the target-action pair and the action method is dateChanged:. I then added the date picker to the view.

I also added some log code here and there and implemented the dateChanged: method.

BNRChangeDateViewController.m…

#import "BNRChangeDateViewController.h"
#import "BNRItem.h"
#import "BNRDetailViewController.h"

@interface BNRChangeDateViewController ()
@end

@implementation BNRChangeDateViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization  
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    // allocate and initilize date picker and set frame
    _datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 50, 200, 100)];
    
    // sets the date picker's mode
    _datePicker.datePickerMode = UIDatePickerModeDate;
    
    // sets the date picker's date to the date of the item on previous view
    _datePicker.date = self.item.dateCreated;
    
    // configures action for date picker
    [_datePicker addTarget:self action:@selector(dateChanged:) forControlEvents:UIControlEventValueChanged];
    
    // add date picker to view
    [self.view addSubview:_datePicker];
    
    NSLog(@"View Loaded");
}

-(void)viewWillDisappear:(BOOL)animated
{
    [self.datePicker endEditing:YES];
    
    BNRItem *item = self.item;
    [item changeDate: self.datePicker.date];
  
    NSLog(@"View Popped");
}

-(IBAction)dateChanged:(id)sender
{
    NSLog(@"Date Selected");
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

I then added a Change Date button to the .xib of the detail view controller and added it as a property of the class. I set the action of the button to push the BNRChangeDateViewController on top of the stack to show that view. I did a few other tricks here is the code…

BNRDetailViewController.h

#import <UIKit/UIKit.h>

@class BNRItem;
@class BNRChangeDateViewController;

@interface BNRDetailViewController : UIViewController

@property (nonatomic, strong) BNRItem *item;
@property (nonatomic, strong) BNRChangeDateViewController *changeDateVC;

@end

BNRDetailViewController.m

#import "BNRDetailViewController.h"
#import "BNRItem.h"
#import "BNRImageStore.h"
#import "BNRChangeDateViewController.h"

@interface BNRDetailViewController () <UIImagePickerControllerDelegate, UINavigationControllerDelegate, UITextFieldDelegate>

@property (weak, nonatomic) IBOutlet UITextField *nameField;
@property (weak, nonatomic) IBOutlet UITextField *serialNumberField;
@property (weak, nonatomic) IBOutlet UITextField *valueField;
@property (weak, nonatomic) IBOutlet UILabel *dateField;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UIToolbar *toolbar;
@property (weak, nonatomic) IBOutlet UIButton *changeDateButton;

@end

@implementation BNRDetailViewController

- (IBAction)takePicture:(id)sender
{
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc]init];
    
    // If the device has a camera, take a picture, otherwise,
    // just pick from photo library
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
    } else {
        imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    }
    
    imagePicker.delegate = self;
    
    // Place image picker on the screen
    [self presentViewController:imagePicker animated:YES completion:nil];
}


- (IBAction)backgroundTapped:(id)sender
{
    [self.view endEditing:YES];
}

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    // Get picked image from info dictionary
    UIImage *image = info[UIImagePickerControllerOriginalImage];
    
    // Store the image in the BNRImageStore for this key
    [[BNRImageStore sharedStore] setImage:image forKey:self.item.itemKey];
    
    //  Put that image onto the screen in image view
    self.imageView.image = image;
    
    // Take image picker off screen -
    // you must call this dismiss method
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (IBAction)changeDateButtonClicked:(id)sender
{
     _changeDateVC = [[BNRChangeDateViewController alloc] init];
    
    _changeDateVC.item = self.item;
    
    [self.navigationController pushViewController:_changeDateVC animated:YES];
}


-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField resignFirstResponder];
    return YES;
}

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear];
    
    BNRItem *item = self.item;
    
    
    self.nameField.text = item.itemName;
    self.serialNumberField.text = item.serialNumber;
    self.valueField.text = [NSString stringWithFormat:@"%d", item.valueInDollars];
    
    // You need an NSDateFormatter that will turn a date into a simple date string
    static NSDateFormatter *dateFormater = nil;
    
    if (!dateFormater) {
        dateFormater = [[NSDateFormatter alloc] init];
        dateFormater.dateStyle = NSDateFormatterMediumStyle;
        dateFormater.timeStyle = NSDateFormatterNoStyle;
    }
    
    // Use filtered NSDate object to set daateLabels contents
    if (!self.changeDateVC){
        NSLog(@"No CDVC");
        
       self.dateField.text = [dateFormater stringFromDate:item.dateCreated];
        
    } else {
        
        //[self.item changeDate: self.changeDateVC.datePicker.date];
        self.dateField.text = [dateFormater stringFromDate:item.dateCreated];
        self.changeDateVC.item = self.item;
    
    }
    NSString *imageKey = self.item.itemKey;
    
    // Get the image for its image key from the image store
    UIImage *imageToDisplay = [[BNRImageStore sharedStore] imageForKey];
    
    // Use that image to put on the screen in the imageView
    self.imageView.image = imageToDisplay;   
}

-(void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear];
    
    // clear first responder
    [self.view endEditing:YES];
    
    // "Save" changes to item
    BNRItem *item = self.item;
    item.itemName = self.nameField.text;
    item.serialNumber = self.serialNumberField.text;
    item.valueInDollars = [self.valueField.text intValue];
}

-(void)setItem:(BNRItem *)item
{
    _item = item;
    self.navigationItem.title = _item.itemName;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.valueField resignFirstResponder];
}

// Text field delegate method when field is in editing mode
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    // Create a View for done button
    UIToolbar *keyboardDoneButtonView = [[UIToolbar alloc] init];
    [keyboardDoneButtonView sizeToFit];
    
    // create a button for done button view and assign an action when button is tapped
    UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:@"DONE"
                                                                   style:UIBarButtonItemStyleBordered
                                                                  target:self
                                                                  action:@selector(doneClicked:)];
    
    // add the done button to the done button view
    [keyboardDoneButtonView setItems:[NSArray arrayWithObjects:doneButton, nil]];
    
    // add the done button view to the keyboard when the value field is in editing mode
    self.valueField.inputAccessoryView = keyboardDoneButtonView;

}

// method to clear keyboard off view when done button is tapped
-(IBAction)doneClicked:(id)sender
{
    NSLog(@"Done Button Clicked");
    [self.view endEditing:YES];
}

@end

I know I said a lot lol but explaining this stuff kind of helps me as a review. Comments and questions are welcomed…