My app doesn't show anything in the iOS simulator - ios

I am learning about how this article
program description
At the end of the page of Table View Controller you have to run you're app to see if everything works but i don't see anything in the iOS simulator besides that everything is black and at the top carrier and time.
One time i'm getting the error Locations[1203:fb03] Applications are expected to have a root view controller at the end of application launch
And another time
App delegate header file:
#import <UIKit/UIKit.h>
UINavigationController *navigationController;
#interface LocationsAppDelegate : UIResponder <UIApplicationDelegate>
#property (nonatomic, retain) UINavigationController *navigationController;
#property (strong, nonatomic) UIWindow *window;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
App delegate Implementation file:
#import "LocationsAppDelegate.h"
#import "RootViewController.h"
#implementation LocationsAppDelegate;
#synthesize navigationController;
#synthesize window = _window;
#synthesize managedObjectContext = __managedObjectContext;
#synthesize managedObjectModel = __managedObjectModel;
#synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
RootViewController *rootViewController = [[RootViewController alloc]
initWithStyle:UITableViewStylePlain];
NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
// Handle the error.
}
// Pass the managed object context to the view controller.
rootViewController.managedObjectContext = context;
UINavigationController *aNavigationController = [[UINavigationController alloc]
initWithRootViewController:rootViewController];
self.navigationController = aNavigationController;
[_window addSubview:[navigationController view]];
[_window makeKeyAndVisible];
[rootViewController release];
[aNavigationController release];
return YES;
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil)
{
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
#pragma mark - Core Data stack
/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *)managedObjectContext
{
if (__managedObjectContext != nil)
{
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created from the application's model.
*/
- (NSManagedObjectModel *)managedObjectModel
{
if (__managedObjectModel != nil)
{
return __managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Locations" withExtension:#"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil)
{
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Locations.sqlite"];
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
#pragma mark - Application's Documents directory
/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
#end
View controller header file:
#import <CoreLocation/CoreLocation.h>
#interface RootViewController : UITableViewController <CLLocationManagerDelegate> {
NSMutableArray *eventsArray;
NSManagedObjectContext *managedObjectContext;
CLLocationManager *locationManager;
UIBarButtonItem *addButton;
}
#property (nonatomic, retain) NSMutableArray *eventsArray;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) UIBarButtonItem *addButton;
#end
View controller implementation file
//
// RootViewController.m
// Locations
#import "RootViewController.h"
#implementation RootViewController
#synthesize eventsArray;
#synthesize managedObjectContext;
#synthesize addButton;
#synthesize locationManager;
- (CLLocationManager *)locationManager {
if (locationManager != nil) {
return locationManager;
}
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.delegate = self;
return locationManager;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
addButton.enabled = YES;
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error {
addButton.enabled = NO;
}
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
// Set the title.
self.title = #"Locations";
// Set up the buttons.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self action:#selector(addEvent)];
addButton.enabled = NO;
self.navigationItem.rightBarButtonItem = addButton;
// Start the location manager.
[[self locationManager] startUpdatingLocation];
}
- (void)viewDidUnload {
self.eventsArray = nil;
self.locationManager = nil;
self.addButton = nil;
}
- (void)dealloc {
[managedObjectContext release];
[eventsArray release];
[locationManager release];
[addButton release];
[super dealloc];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
#warning Potentially incomplete method implementation.
// Return the number of sections.
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
#warning Incomplete method implementation.
// Return the number of rows in the section.
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
*/
}
#end
Can someone please help me out??

I feel like Captain Obvious, but you forgot to set window.rootViewController.

Related

Cant perform delegation

I have a table view controller and a view controller.
StackTableViewController - list of strings
HomeViewController - empty view controller with a label
The HomeViewController label should present always the first sting of the StackTableViewController.
I need to make sure if the first string is deleted to present the new first string.
And this is where I have the problem...if I delete the first string and going back to the HomeViewController, the label is still the string I just deleted....And if I terminate the app and open it again, the correct string shown in the label.
This is How I did it so far:
this is the relevant methods in my StackTableViewController.h + .m:
#protocol StackTableViewControllerDelegate <NSObject>
#optional
-(void)didDeleteObject;
#end
#interface StackTableViewController : UITableViewController <UITableViewDataSource,UITableViewDelegate>
#property (strong,nonatomic) id<StackTableViewControllerDelegate> delegate;
#property (strong, nonatomic) NSString *currentTarget;
#end
#import "StackTableViewController.h"
#import "Target.h"
#import "StackTableViewCell.h"
#import "HomeViewController.h"
#import "CoreDataStack.h"
#interface StackTableViewController () <NSFetchedResultsControllerDelegate>
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultController;
#end
#implementation StackTableViewController
- (id)init {
self = [super initWithNibName:#"StackTableViewController" bundle:nil];
if (self) {
// Do something
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];
CoreDataStack *stack = [CoreDataStack defaultStack];
[[stack managedObjectContext] deleteObject:target];
[stack saveContext];
if ([_delegate respondsToSelector:#selector(didDeleteObject)]) {
[_delegate didDeleteObject];
}
}
And this is the relevant methods in the HomeViewController.h + .m:
#import <UIKit/UIKit.h>
#import "StackTableViewController.h"
#interface HomeViewController : UIViewController {
StackTableViewController *stackTableViewController;
}
#property (strong, nonatomic) IBOutlet UILabel *homeLabel;
- (IBAction)goToStack:(id)sender;
#import "StackTableViewController.h"
#interface HomeViewController () <StackTableViewControllerDelegate>
#end
#implementation HomeViewController
- (id)init {
self = [super initWithNibName:#"HomeViewController" bundle:nil];
if (self) {
// Do something
stackTableViewController = [[StackTableViewController alloc] init];
stackTableViewController.delegate = self;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self.navigationController setNavigationBarHidden:YES];
self.homeLabel.font = [UIFont fontWithName:#"Candara-Bold" size:40];
self.homeLabel.text = stackTableViewController.currentTarget;
}
- (void)didDeleteObject {
self.homeLabel.text = stackTableViewController.currentTarget;
}
- (IBAction)goToStack:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
CoreDataStack.h +.m:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface CoreDataStack : NSObject
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
+ (instancetype)defaultStack;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
#import "CoreDataStack.h"
#implementation CoreDataStack
#pragma mark - Core Data stack
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
+ (instancetype)defaultStack {
static CoreDataStack *defaultStack;
static dispatch_once_t onceTocken;
dispatch_once (&onceTocken, ^{
defaultStack = [[self alloc] init];
});
return defaultStack;
}
- (NSURL *)applicationDocumentsDirectory {
// The directory the application uses to store the Core Data store file. This code uses a directory named "digitalCrown.Treats" in the application's documents directory.
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (NSManagedObjectModel *)managedObjectModel {
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Treats" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Create the coordinator and store
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Treats.sqlite"];
NSError *error = nil;
NSString *failureReason = #"There was an error creating or loading the application's saved data.";
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = #"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:#"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
#pragma mark - Core Data Saving support
- (void)saveContext {
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSError *error = nil;
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
#end
Please help me to solve this, I was tying allot of ways but probably i'm missing something that got to do with view controller lifecycle or something.
(the CoreDataStack is a singleton)
tnx!!
I have noticed that you haven't exposed where and how do you go back as you said here:
And this is where I have the problem...if I delete the first string
and going back to the HomeViewController, the label is still the
string I just deleted
You have two choices to fix it:
1) Use viewWillAppear function and update the required text in it.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// get the most recent updates and assign to the UI
self.homeLabel.text = stackTableViewController.currentTarget;
}
So either you have just loaded this UI or coming back from the next UI, this will be going to help to get the latest updates.
2) Before calling popViewControllerAnimated make sure you have updated text.
if (_delegate && [_delegate respondsToSelector:#selector(didDeleteObject)])
{
// updated the UI through delegate
[_delegate didDeleteObject];
}
// This should be call when your work is done, since
// It will start ending the session of this UI so it will obviously
// miss the track of the `_delegate` variable.
[self.navigationController popViewControllerAnimated:YES];
Hope it helps!
I think you just need to reset your currentTarget property after you delete the object:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];
CoreDataStack *stack = [CoreDataStack defaultStack];
[[stack managedObjectContext] deleteObject:target];
[stack saveContext];
// The FRC should recognise that the deletion has happened, and consequently have updated its
// indexes, so the following will access the NEW first item, even if it has just changed:
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
if ([_delegate respondsToSelector:#selector(didDeleteObject)]) {
[_delegate didDeleteObject];
}
}
I think you'd be better off setting up your variables differently. Specifically, it seems like you would be better off to have a singleton object that holds and manages the stack for you, but here's a way to do what you have set up. I've written a basic app that includes all of its UI in code. Here are the pertinent files:
// AppDelegate.h
// StackTableTesting
#import <UIKit/UIKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
// AppDelegate.m
// StackTableTesting
#import "AppDelegate.h"
#import "HomeViewController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
HomeViewController *vc = [[HomeViewController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
nav.navigationBar.translucent = NO;
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
return YES;
}
#end
// Created by Michael McEvoy on 12/23/14.
// Copyright (c) 2014 Mustard Seed Software LLC. All rights reserved.
#import <UIKit/UIKit.h>
#import "StackTableViewController.h"
#interface HomeViewController : UIViewController
#end
// HomeViewController.m
// StackTableTesting
#import "HomeViewController.h"
#import "StackTableViewController.h"
#interface HomeViewController () <StackTableViewControllerDelegate> {
}
#pragma mark -
#pragma mark - Private Properties
#property (strong, nonatomic) StackTableViewController *stackTableViewController;
#property (strong, nonatomic) UILabel *homeLabel;
#end
#pragma mark -
#pragma mark - Implementation
#implementation HomeViewController
#pragma mark -
#pragma mark - Initialization
- (instancetype)init {
self = [super init];
if (self != nil) {
self.stackTableViewController = [[StackTableViewController alloc] init];
self.stackTableViewController.delegate = self;
}
return self;
}
#pragma mark -
#pragma mark - View Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUserInterface];
}
#pragma mark -
#pragma mark - StackTableViewControllerDelegate Protocol Methods
- (void)didDeleteObject {
self.homeLabel.text = self.stackTableViewController.currentTarget;
}
#pragma mark -
#pragma mark - Button Presses
- (void)goToStack {
[self.navigationController pushViewController:self.stackTableViewController animated:YES];
}
#pragma mark -
#pragma mark - UI Setup
// This is because there's no Storyboard
- (void)setupUserInterface {
self.homeLabel = [[UILabel alloc] init];
self.homeLabel.font = [UIFont fontWithName:#"Candara-Bold" size:40];
self.homeLabel.frame = CGRectMake(20, 20, 200, 50);
self.homeLabel.text = self.stackTableViewController.currentTarget;
self.homeLabel.textColor = [UIColor blackColor];
[self.view addSubview:self.homeLabel];
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.frame = CGRectMake(20, 80, 200, 50);
[button addTarget:self action:#selector(goToStack) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"Go To Stack" forState:UIControlStateNormal];
[self.view addSubview:button];
self.view.backgroundColor = [UIColor whiteColor];
}
#end
// StackTableViewController.h
// StackTableTesting
#import <UIKit/UIKit.h>
#protocol StackTableViewControllerDelegate <NSObject>
- (void)didDeleteObject;
#end
#interface StackTableViewController : UITableViewController {
}
#pragma mark -
#pragma mark - Properties
#property (weak, nonatomic) id <StackTableViewControllerDelegate> delegate;
#property (copy, nonatomic) NSString *currentTarget;
#end
// StackTableViewController.m
// StackTableTesting
#import "StackTableViewController.h"
#interface StackTableViewController () {
}
#pragma mark -
#pragma mark - Private Properties
#property (strong, nonatomic) NSMutableArray *stack;
#end
#pragma mark -
#pragma mark - Implementation
#implementation StackTableViewController
#pragma mark -
#pragma mark - Initialization
- (instancetype)init {
self = [super init];
if (self != nil) {
self.stack = [NSMutableArray array];
for (int i = 0; i < 10; i = i + 1) {
[self.stack addObject:[NSString stringWithFormat:#"Item %d", i + 1]];
self.currentTarget = self.stack[0];
}
}
return self;
}
#pragma mark -
#pragma mark - View Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"cell"];
}
#pragma mark -
#pragma mark - UITableViewDataSource Protocol Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.stack.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.textLabel.text = self.stack[indexPath.row];
return cell;
}
#pragma mark -
#pragma mark - UITableViewDelegate Protocol Methods
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
[self.stack removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
self.currentTarget = self.stack[0];
if ([_delegate respondsToSelector:#selector(didDeleteObject)]) {
[_delegate didDeleteObject];
}
}
#end
I think this setup does what you're trying to do, based on your question.
Just set the label value again when HomeViewController appear again. That should work since you said that re-launching the app. solves the problem. This should work too.
- (void)viewWillAppear:(BOOL)animated {
self.homeLabel.text = stackTableViewController.currentTarget;
}
- (id)init {
self = [super initWithNibName:#"HomeViewController" bundle:nil];
if (self) {
// Do something
stackTableViewController = [[StackTableViewController alloc] init];
stackTableViewController.delegate = self;
}
return self;
}
Here, you create a StackTableViewController and set self as the delegate. This is fine.
- (IBAction)goToStack:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
Here, you create a brand new StackTableViewController and push it, without setting the delegate object. Any changes you do in the pushed view controller won't be fed back to the home view controller because the delegate is not set.
Either push your existing stackViewController, or set the delegate on your newly created one.
As an additional point, this:
#property (strong,nonatomic) id<StackTableViewControllerDelegate> delegate;
Coupled with this:
#interface HomeViewController : UIViewController {
StackTableViewController *stackTableViewController;
}
And the fact you're setting the delegate of the stack table view controller to the home view controller (which owns the stack table view controller) means you're creating a strong reference cycle. Delegates are normally weak references for this purpose.

How should I perform this delegate properly?

I have a table view controller and a view controller.
StackTableViewController - list of strings
HomeViewController - empty view controller with a label
The HomeViewController label should present always the first sting of the StackTableViewController.
I need to make sure if the first string is deleted to present the new first string.
And this is where I have the problem...if I delete the first string and going back to the HomeViewController, the label is still the string I just deleted....And if I terminate the app and open it again, the correct string shown in the label.
This is How I did it so far:
this is the relevant methods in my StackTableViewController.h + .m:
#protocol StackTableViewControllerDelegate <NSObject>
#optional
-(void)didDeleteObject;
#end
#interface StackTableViewController : UITableViewController <UITableViewDataSource,UITableViewDelegate>
#property (strong,nonatomic) id<StackTableViewControllerDelegate> delegate;
#property (strong, nonatomic) NSString *currentTarget;
#end
#import "StackTableViewController.h"
#import "Target.h"
#import "StackTableViewCell.h"
#import "HomeViewController.h"
#import "CoreDataStack.h"
#interface StackTableViewController () <NSFetchedResultsControllerDelegate>
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultController;
#end
#implementation StackTableViewController
- (id)init {
self = [super initWithNibName:#"StackTableViewController" bundle:nil];
if (self) {
// Do something
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];
CoreDataStack *stack = [CoreDataStack defaultStack];
[[stack managedObjectContext] deleteObject:target];
[stack saveContext];
if ([_delegate respondsToSelector:#selector(didDeleteObject)]) {
[_delegate didDeleteObject];
}
}
And this is the relevant methods in the HomeViewController.h + .m:
#import <UIKit/UIKit.h>
#import "StackTableViewController.h"
#interface HomeViewController : UIViewController {
StackTableViewController *stackTableViewController;
}
#property (strong, nonatomic) IBOutlet UILabel *homeLabel;
- (IBAction)goToStack:(id)sender;
#import "StackTableViewController.h"
#interface HomeViewController () <StackTableViewControllerDelegate>
#end
#implementation HomeViewController
- (id)init {
self = [super initWithNibName:#"HomeViewController" bundle:nil];
if (self) {
// Do something
stackTableViewController = [[StackTableViewController alloc] init];
stackTableViewController.delegate = self;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self.navigationController setNavigationBarHidden:YES];
self.homeLabel.font = [UIFont fontWithName:#"Candara-Bold" size:40];
self.homeLabel.text = stackTableViewController.currentTarget;
}
- (void)didDeleteObject {
self.homeLabel.text = stackTableViewController.currentTarget;
}
- (IBAction)goToStack:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
CoreDataStack.h +.m:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface CoreDataStack : NSObject
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
+ (instancetype)defaultStack;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
#import "CoreDataStack.h"
#implementation CoreDataStack
#pragma mark - Core Data stack
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
+ (instancetype)defaultStack {
static CoreDataStack *defaultStack;
static dispatch_once_t onceTocken;
dispatch_once (&onceTocken, ^{
defaultStack = [[self alloc] init];
});
return defaultStack;
}
- (NSURL *)applicationDocumentsDirectory {
// The directory the application uses to store the Core Data store file. This code uses a directory named "digitalCrown.Treats" in the application's documents directory.
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (NSManagedObjectModel *)managedObjectModel {
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Treats" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Create the coordinator and store
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Treats.sqlite"];
NSError *error = nil;
NSString *failureReason = #"There was an error creating or loading the application's saved data.";
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = #"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:#"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
#pragma mark - Core Data Saving support
- (void)saveContext {
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSError *error = nil;
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
#end
Please help me to solve this, I was tying allot of ways but probably i'm missing something that got to do with view controller lifecycle or something.
(the CoreDataStack is a singleton)
tnx!!
What you can do is to use one Action for both an check the sender and the segue to know where is it coming from:
- (void)unwindFromModal:(UIStoryboardSegue *)unwindSegue {
if unwindSegue.identifier == #"createModal" {
NSLog(#"Got home from create page");
}
if unwindSegue.identifier == #"stackModal" {
NSLog(#"Got home from stack page");
}
}
- (IBAction)presentModal:(UIButton*)sender {
if sender.tag == 0 {
[self performSegueWithIdentifier:#"createModal" sender:self];
}
if sender.tag == 1 {
[self performSegueWithIdentifier:#"stackModal" sender:self];
}
}
You can use String Constants in the tags to make more readable and a switch if you prefer too
There could be two issues need to be fixed here.
Delegate method didDeleteObject is not called at all. In goToStack method you create a new StackTableViewController but forget to set its delegate, while you also have a global variable stackTableViewController instance. I think you meant to push the global one onto the stack.
In commitEditingStyle tableview delegate method, you forget to update the currentTarget property which is used to update the label text, you can try to update that property and see what would happen.
For 1, you can change the goToStack function like this:
[self.navigationController pushViewController:stackTableViewController animated:YES];
Which means StackTableViewController *vc = [[StackTableViewController alloc] init]; should be removed.
For 2, in commitEditingStyle method, after [stack saveContext].
[stack saveContext];
//Please add the following code.
NSIndexPath *theIndexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:theIndexPath];
self.currentTarget = current.body;
Your problem is that you don't update StackTableViewController property currentTarget in commitEditingStyle. Just update code in StackTableViewController.m:
Also if you use same code more than 2 times - better move it to separate function
- (id)init {
self = [super initWithNibName:#"StackTableViewController" bundle:nil];
if (self) {
// Do something
[self.fetchedResultController performFetch:nil];
[self updateCurrentTarget];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
[self updateCurrentTarget];
}
- (void)updateCurrentTarget
{
if (self.fetchedResultsController.sections.count == 0 && [self.fetchedResultsController.sections.firstObject count] == 0) {
self.currentTarget = nil;
} else {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
}
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
Target *target = [self.fetchedResultController objectAtIndexPath:indexPath];
CoreDataStack *stack = [CoreDataStack defaultStack];
[[stack managedObjectContext] deleteObject:target];
[stack saveContext];
[self updateCurrentTarget];
if ([_delegate respondsToSelector:#selector(didDeleteObject)]) {
[_delegate didDeleteObject];
}
}
You need make 2 changes:
In goToStack: add vc.delegate = self before pushViewController:
In your StackTableViewController tableView: commitEditingStyle: update currentTarget before invoke [_delegate didDeleteObject]
- (IBAction)goToStack:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
This method should be as below:
- (IBAction)goToStack:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc] init];
vc.delegate = self.
[self.navigationController pushViewController:vc animated:YES];
}
The reason for this is that you've setup HomeVC as delegate of StackTable in the init method, but you aren't using the same instance of StackTable and initializing a new instance.

Saving data in one view controller and displaying it in another

I am currently developing an app the needs to have an initial setting screen (name, date, amount of deposit, and percentage). I have created a view controller that will add and then save to core data. I can also retrieve the information.
What I need next is to be able to pop into another view controller and enter continuing number for the same person. Whenever i enter data into the second view controller it comes back as an addition as if it were a new person. I need some help to figure it out as i am still new and learning.
Below is the .h and .m files of the two view controllers.
ForexDetailViewController.h
#import <UIKit/UIKit.h>
#interface ForexDetailViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *nameTextField;
#property (weak, nonatomic) IBOutlet UITextField *startamountTextField;
#property (weak, nonatomic) IBOutlet UITextField *startmonthTextField;
#property (strong, nonatomic) IBOutlet UITextField *startpercentTextField;
#property (weak, nonatomic) IBOutlet UITextField *endmonth1year1TextField;
#property (weak, nonatomic) IBOutlet UITextField *endpercentmonth1year1TextField;
#property (strong) NSManagedObject *device;
- (IBAction)cancel:(id)sender;
- (IBAction)save:(id)sender;
- (IBAction)textFieldReturn:(id)sender;
- (IBAction)calcultae;
#end
ForexDetailViewController.m
#import "ForexDetailViewController.h"
#interface ForexDetailViewController ()
#end
#implementation ForexDetailViewController
- (IBAction)textFieldReturn:(id)sender
{
[sender resignFirstResponder];
}
#synthesize device;
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (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.
if (self.device) {
[self.nameTextField setText:[self.device valueForKey:#"name"]];
[self.startamountTextField setText:[self.device valueForKey:#"startamount"]];
[self.startmonthTextField setText:[self.device valueForKey:#"startmonth"]];
[self.startpercentTextField setText:[self.device valueForKey:#"startpercent"]];
[self.endmonth1year1TextField setText:[self.device valueForKey:#"endmonth1year1"]];
[self.endpercentmonth1year1TextField setText:[self.device valueForKey:#"endpercentmonth1year1"]];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)cancel:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)save:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
if (self.device) {
// Update existing device
[self.device setValue:self.nameTextField.text forKey:#"name"];
[self.device setValue:self.startamountTextField.text forKey:#"startamount"];
[self.device setValue:self.startmonthTextField.text forKey:#"startmonth"];
[self.device setValue:self.startpercentTextField.text forKey:#"startpercent"];
[self.device setValue:self.endmonth1year1TextField.text forKey:#"startpercent"];
[self.device setValue:self.endpercentmonth1year1TextField.text forKey:#"endpercentmonth1year1"];
} else {
// Create a new device
NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:#"Calculations" inManagedObjectContext:context];
[newDevice setValue:self.nameTextField.text forKey:#"name"];
[newDevice setValue:self.startamountTextField.text forKey:#"startamount"];
[newDevice setValue:self.startmonthTextField.text forKey:#"startmonth"];
[newDevice setValue:self.startpercentTextField.text forKey:#"startpercent"];
[newDevice setValue:self.endmonth1year1TextField.text forKey:#"endmonth1year1"];
[newDevice setValue:self.endpercentmonth1year1TextField.text forKey:#"endpercentmonth1year1"];
}
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
TimeLineViewController.h
#import <UIKit/UIKit.h>
#interface TimeLineViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *startamountTextField;
#property (weak, nonatomic) IBOutlet UITextField *endmonth1year1TextField;
#property (weak, nonatomic) IBOutlet UITextField *endpercentmonth1year1TextField;
#property (strong) NSManagedObject *device;
- (IBAction)cancel:(id)sender;
- (IBAction)save:(id)sender;
- (IBAction)textFieldReturn:(id)sender;
#end
TimeLineViewController.m
#import "TimeLineViewController.h"
#interface TimeLineViewController ()
#end
#implementation TimeLineViewController
- (IBAction)textFieldReturn:(id)sender
{
[sender resignFirstResponder];
}
#synthesize device;
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (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.
if (self.device) {
[self.startamountTextField setText:[self.device valueForKey:#"startamount"]];
[self.endmonth1year1TextField setText:[self.device valueForKey:#"endmonthe1year1"]];
[self.endpercentmonth1year1TextField setText:[self.device valueForKey:#"endpercentmonth1year1"]];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)cancel:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)save:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
if (self.device) {
// Update existing device
[self.device setValue:self.startamountTextField.text forKey:#"startamount"];
[self.device setValue:self.endmonth1year1TextField.text forKey:#"endmonth1year1"];
[self.device setValue:self.endpercentmonth1year1TextField.text forKey:#"endpercentmonth1year1"];
} else {
// Create a new device
NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:#"Calculations" inManagedObjectContext:context];
[newDevice setValue:self.startamountTextField.text forKey:#"startamount"];
[newDevice setValue:self.endmonth1year1TextField.text forKey:#"endmonth1year1"];
[newDevice setValue:self.endpercentmonth1year1TextField.text forKey:#"endpercentmonth1year1"];
}
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
ForexViewController.m
#import "ForexViewController.h"
#import "ForexDetailViewController.h"
#interface ForexViewController ()
#property (strong) NSMutableArray *devices;
#end
#implementation ForexViewController
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Calculations"];
self.devices = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return self.devices.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSManagedObject *device = [self.devices objectAtIndex:indexPath.row];
[cell.textLabel setText:[NSString stringWithFormat:#"%#", [device valueForKey:#"name"]]];
[cell.detailTextLabel setText:[device valueForKey:#"startamount"]];
[cell.detailTextLabel setText:[device valueForKey:#"startmonth"]];
[cell.detailTextLabel setText:[device valueForKey:#"startpercent"]];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete object from database
[context deleteObject:[self.devices objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
// Remove device from table view
[self.devices removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
}
#pragma mark - Segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"UpdateDevice"]) {
NSManagedObject *selectedDevice = [self.devices objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
ForexDetailViewController *destViewController = segue.destinationViewController;
destViewController.device = selectedDevice;
}
}
#end
Where is your code that shows how you show each view?
If you're doing this via Storyboard segue's, you should be setting the device property on the view controllers when you're preparing for segue.
Currently, I don't see how self.device is getting set for either of these view controllers so each time the view loads, it think's there isn't a device and therefore creates a new record for one.
A quick example with a storyboard segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"changeDeviceSettings"]) {
SomeViewController *vc = segue.destinationViewController;
vc.device = selectedDeviceGoesHere;
}
}

iOS (iPhone/iPad) SDK - Using a JSON parser with Twitter's user_timeline

Ok, here is my code:
(appname)AppDelegate.h:
#import <UIKit/UIKit.h>
#class TwitterViewContoller;
#interface <appname>AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UITabBarController *rootController;
TwitterViewContoller *viewController;
NSMutableData *responseData;
NSMutableArray *tweets;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *rootController;
#property (nonatomic, retain) IBOutlet TwitterViewContoller *viewController;
#property (nonatomic, retain) NSMutableArray *tweets;
#end
(appname)AppDelegate.m:
#import "<appname>AppDelegate.h"
#import "TwitterViewContoller.h"
#import "SBJson.h"
#implementation <appname>AppDelegate
#synthesize window = _window;
#synthesize rootController;
#synthesize viewController;
#synthesize tweets;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
responseData = [[NSMutableData data] retain];
tweets = [NSMutableArray array];
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:#"http://api.twitter.com/1/statuses/user_timeline.json?screen_name=USER_NAME_ID"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
//[window addSubview:rootController.view];
//[window makeKeyAndVisible];
return YES;
}
#pragma mark NSURLConnection delegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
//NSDictionary *results = [responseString JSONValue]; <---This...
//NSArray *allTweets = [results objectForKey:#"results"]; <--- and this was original code but it caused an exception,
NSArray *allTweets = [responseString JSONValue]; //<-- So I used this instead.
NSLog(#"THE ARRAY = %#", allTweets); //<-- THE ARRAY IS SHOWING FINE IN THE OUTPUT LOG
[viewController setTweets:allTweets];
[self.window addSubview:rootController.view];
[self.window makeKeyAndVisible];
}
- (void)dealloc {
[_window release];
[rootController release];
[viewController release];
[super dealloc];
}
#end
TwitterViewContoller.h: (yes, I know I spelt it wrong - lol)
#import <UIKit/UIKit.h>
#import "SBJson.h"
#interface TwitterViewContoller : UIViewController {
IBOutlet UILabel *label;
NSArray *tweets;
IBOutlet UITableView *tview;
}
#property(nonatomic, retain) IBOutlet UILabel *label;
#property(nonatomic, retain) NSArray *tweets;
#end
TwitterViewContoller.m:
#import "TwitterViewContoller.h"
#import "Tweet.h"
#implementation TwitterViewContoller
#synthesize label;
#synthesize tweets;
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return 20;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 80;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
NSLog(#"THE ARRAY = %#", tweets); //<--ARRAY IS NULL <-- <-- <--
NSDictionary *aTweet = [tweets objectAtIndex:[indexPath row]];
cell.textLabel.text = [aTweet objectForKey:#"text"];
cell.textLabel.adjustsFontSizeToFitWidth = YES;
cell.textLabel.font = [UIFont systemFontOfSize:12];
cell.textLabel.minimumFontSize = 10;
cell.textLabel.numberOfLines = 4;
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.detailTextLabel.text = [aTweet objectForKey:#"screen_name"];
NSURL *url = [NSURL URLWithString:[aTweet objectForKey:#"profile_image_url"]];
NSData *data = [NSData dataWithContentsOfURL:url];
cell.imageView.image = [UIImage imageWithData:data];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
tweets = [[NSArray alloc]init];
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void) dealloc {
[tweets release];
[super dealloc];
}
#end
The problem is that my UITableView is showing up but none of my tweets are. I have noticed that the "tweets" array in TwitterViewContoller (I know I spelt it wrong) is empty (the null problem is fixed) but "allTweets" in my AppDelegate isn't empty. Any ideas?
Test to ensure that in your app delegate, the viewController property is not nil. If you have miswired it in IB (I don't see any instantiation of it in your app delegate), it will silently fail when you call setTweets.
Also, if your view controller is visible and you re-set the tweets property, the table view won't update itself. Instead of synthesizing your tweets property, write your own getter and setter, like so (you could also use KVO for this purpose if you like)
-(NSMutableArray*)tweets {
return [[tweets retain] autorelease];
}
-(void)setTweets:(NSMutableArray*)newTweets {
if(newTweets != tweets) {
[newTweets retain];
[tweets release];
tweets = newTweets;
[tView reloadData];
}
}
As an aside, you should have -tableView:numberOfRowsInSection: return [tweets count] rather than a fixed number, and it isn't necessary to implement -tableView:heightForRowAtIndexPath: if your rows are all the same height -- you can just set the rowHeight property in IB or in code on the table view.
Update
If your view controller property isn't getting populated, it might be easiest to just load and add it manually in -application:didFinishLaunchingWithOptions -- I think your current approach of delaying the display of any interface until the web request finishes is conceptually problematic. What happens if the network isn't available? Here's some code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// ... omitting the first few lines
// let's make sure that we have the tab bar controller, at least
NSAssert(nil != self.rootViewController, #"tab bar controller not hooked up!");
self.viewController = [[[TwitterViewContoller alloc] initWithNibName:#"TwitterViewContoller" andBundle:nil] autorelease];
self.rootViewController.viewControllers = [NSArray arrayWithObject:self.viewController];
// this is now the Right Way to set the root view for your app, in iOS 4.0 and later
self.window.rootViewController = self.rootViewController;
[self.window makeKeyAndVisible];
}
There are a lot of ways that you can confuse yourself when you're starting a new project. I like to customize all of my views to have hideous background colors at first so I always know if they're on screen or not -- using ugly colors helps ensure that I don't forget to change them later.

Core Data app don't load data from persistent store

I've any problems for app I'm developing...
I'm using Core Data and I just write initial code...
But one of my problem is: Core Data won't load data stored in persistent store...
This is my code!
MyWishesAppDelegate.h
#import UIKit/UIKit.h
#import CoreData/CoreData.h
#interface MyWishesAppDelegate : NSObject {
UIWindow *window;
UITabBarController *tabBarController;
#private
NSManagedObjectContext *managedObjectContext_;
NSManagedObjectModel *managedObjectModel_;
NSPersistentStoreCoordinator *persistentStoreCoordinator_;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (NSString *)applicationDocumentsDirectory;
#end
MyWishesAppDelegate.m
#import "MyWishesAppDelegate.h"
#implementation MyWishesAppDelegate
#synthesize window;
#synthesize tabBarController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[window insertSubview:tabBarController.view atIndex:0];
[window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions
(such as an incoming phone call or SMS message)
or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application
to its current state in case it is terminated later.
If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
/*
Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background,
optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application {
NSError *error = nil;
if (managedObjectContext_ != nil) {
if ([managedObjectContext_ hasChanges] && ![managedObjectContext_ save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
#pragma mark -
#pragma mark Core Data stack
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext_ != nil) {
return managedObjectContext_;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext_ = [[NSManagedObjectContext alloc] init];
[managedObjectContext_ setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext_;
}
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSString *modelPath = [[NSBundle mainBundle] pathForResource:#"MyWishes" ofType:#"momd"];
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel_;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSURL *storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"MyWishes.sqlite"]];
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator_;
}
#pragma mark -
#pragma mark Application's Documents directory
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
#pragma mark -
#pragma mark Memory management
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
}
- (void)dealloc {
[managedObjectContext_ release];
[managedObjectModel_ release];
[persistentStoreCoordinator_ release];
[tabBarController release];
[window release];
[super dealloc];
}
#end
WishlistViewController.h
#import UIKit/UIKit.h
#import CoreData/CoreData.h
#interface WishlistViewController : UITableViewController {
#private
NSFetchedResultsController *_fetchedResultsController;
}
#property (nonatomic, readonly) NSFetchedResultsController *fetchedResultsController;
-(void)add;
-(IBAction)edit;
#end
WishlistViewController.m
#import "WishlistViewController.h"
#import "MyWishesAppDelegate.h"
#implementation WishlistViewController
#synthesize fetchedResultsController = _fetchedResultsController;
#pragma mark -
#pragma mark Actions
-(void)add {
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
NSError *error;
if (![context save:&error])
NSLog(#"Error saving entity: %#", [error localizedDescription]);
// TODO: instantiate detail editing controller and push onto stack
}
-(IBAction)edit {
BOOL editing = !self.tableView.editing;
self.navigationItem.rightBarButtonItem.enabled = !editing;
self.navigationItem.leftBarButtonItem.title = (editing) ? (#"Done") : (#"Edit");
[self.tableView setEditing:editing animated:YES];
}
#pragma mark -
#pragma mark View lifecycle
-(void)viewDidLoad {
[super viewDidLoad];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Errore caricamento dati"
message:[NSString stringWithFormat:#"L'errore รจ stato: %#", [error localizedDescription]]
delegate:self
cancelButtonTitle:#"Ok!"
otherButtonTitles:nil];
[alert show];
}
}
-(void)viewDidAppear:(BOOL)animated {
UIBarButtonItem *editButton = self.editButtonItem;
[editButton setTarget:self];
[editButton setAction:#selector(edit)];
self.navigationItem.leftBarButtonItem = editButton;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:#selector(add)];
self.navigationItem.rightBarButtonItem = addButton;
[addButton release];
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
}
- (void)dealloc {
[_fetchedResultsController release];
[super dealloc];
}
#pragma mark -
#pragma mark Table View Methods
-(NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView {
NSUInteger count = [[self.fetchedResultsController sections] count];
if (count == 0) {
count = 1;
}
return count;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray *sections = [self.fetchedResultsController sections];
NSUInteger count = 0;
if ([sections count]) {
id sectionInfo = [sections objectAtIndex:section];
count = [sectionInfo numberOfObjects];
}
return count;
}
-(UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *WishlistTableViewCell = #"WishlistTableViewCell";
UITableViewCell *cell = [theTableView dequeueReusableCellWithIdentifier:WishlistTableViewCell];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:WishlistTableViewCell] autorelease];
}
NSManagedObject *oneWish = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [oneWish valueForKey:#"nome"];
/*UIImageView *cellBg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cellBg.png"]];
cell.backgroundView = cellBg;*/
/*cell.detailTextLabel.text = [oneWish valueForKey:#"costo"];*/
return cell;
}
-(void)tableView:(UITableView *)theTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// TODO: instantiate detail editing view controller and push onto stack
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
[context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error;
if (![context save:&error]) {
NSLog(#"Errore non risolto: %#, %#", error, [error userInfo]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Errore salvataggio dati"
message:#"Impossibile salvare dopo aver cancellato un elemento"
delegate:self
cancelButtonTitle:#"Ok!"
otherButtonTitles:nil];
[alert show];
}
}
}
#pragma mark -
#pragma mark Fetched Results Controller
-(NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
MyWishesAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *managedObjectContext = appDelegate.managedObjectContext;
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Wish" inManagedObjectContext:managedObjectContext];
NSString *sectionKey = nil;
NSSortDescriptor *sortByName = [[NSSortDescriptor alloc] initWithKey:#"nome" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortByName, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortByName release];
[sortDescriptors release];
sectionKey = #"nome";
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext
sectionNameKeyPath:sectionKey
cacheName:#"Wish"];
frc.delegate = self;
_fetchedResultsController = frc;
[fetchRequest release];
return _fetchedResultsController;
}
-(void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
-(void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate: {
NSString *sectionKeyPath = [controller sectionNameKeyPath];
if (sectionKeyPath == nil)
break;
NSManagedObject *changedObject = [controller objectAtIndexPath:indexPath];
NSArray *keyParts = [sectionKeyPath componentsSeparatedByString:#"."];
id currentKeyValue = [changedObject valueForKeyPath:sectionKeyPath];
for (int i = 0; i )sectionInfo
atIndex:(NSUInteger)sectionIndex
forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
if (!(sectionIndex == 0 && [self.tableView numberOfSections] == 1) && [self.tableView numberOfRowsInSection:0] == 0)
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
if (!(sectionIndex == 0 && [self.tableView numberOfSections] == 1) && [self.tableView numberOfRowsInSection:0] == 0)
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
break;
case NSFetchedResultsChangeUpdate:
break;
default:
break;
}
}
#pragma mark -
#pragma mark Alert View Delegate
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
exit(-1);
}
#end
Anyone can help me? If there are other problems in this code, you can say it to me...
Start off by running in the debugger with a breakpoint on objc_exception_throw which will cause your app to stop just before it crashes so you can see what the offending line of code is. That will tell you what is causing the problem.
Check the value returned by
#pragma mark Application's Documents directory
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
I believe this should be:
- (NSString *)applicationDocumentsDirectory {
return [(NSArray *)NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
}

Resources