iCloud and CoreData - iphone

I am trying to use iCloud with my iOS app. I have the app working on the individual devices but when I added iCloud nothing happened. I have looked all over the web and have found only one example which I did not understand. My app is iOS 5.0 and use core data to store the pages. Below is my app delegate and my view which I display it in. Sorry for the lack of knowledge when it comes to iPhone dev. Please help.
http://goddess-gate.com/dc2/index.php/post/452
thank you
If anyone know/has a full working project of iCloud+CoreData I belive I can figure it out. Right now I just have code snip it's which I don't even know how they get called... If I have a full project I can step through it, so I can fully understand how it works.
The problem is I don't think anything is being called to update the view with the data and I don't belive it is sending it to the cloud but I don't know what to call...
PageFlipperAppDelegate.h
#import <UIKit/UIKit.h>
#import "PageView.h"
#import "SlideShowViewController.h"
#import "PagesCollectionViewController.h"
#import "UiWindowSubclass.h"
#interface PageFlipperAppDelegate : UIResponder <UIApplicationDelegate>
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (nonatomic, retain, readonly) PagesCollectionViewController *collectionViewController;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
PageFlipperAppDelegate.m
#import "PageFlipperAppDelegate.h"
#implementation PageFlipperAppDelegate
#synthesize window;
#synthesize managedObjectContext, managedObjectModel, persistentStoreCoordinator,collectionViewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque];
[NSThread sleepForTimeInterval:2.75];
collectionViewController = [[PagesCollectionViewController alloc] initWithManagedObjectContext:[self managedObjectContext]];
[(UINavigationController *)[[self window] rootViewController] pushViewController:collectionViewController animated:NO];
[collectionViewController release];
[[self window] makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
//stopping timer since we're going to background
// [(UiWindowSubclass *)self.window stopTimer];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
- (void)applicationDidEnterBackground:(UIApplication *)application { [self saveContext]; }
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationWillTerminate:(UIApplication *)application { [self saveContext];
}
- (void)dealloc
{
[window release];
[managedObjectContext release];
[managedObjectModel release];
[persistentStoreCoordinator release];
[super dealloc];
}
- (void)awakeFromNib
{
}
- (void)saveContext
{
NSError *error = nil;
if ([self managedObjectContext])
{
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
#pragma mark - Core Data stack
- (NSManagedObjectContext *)managedObjectContext
{
if (managedObjectContext != nil)
{
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
//if (IOS_VERSION_GREATER_THAN_OR_EQUAL_TO(#"5.0")) {
NSManagedObjectContext* moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[moc performBlockAndWait:^{
[moc setPersistentStoreCoordinator: coordinator];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(mergeChangesFrom_iCloud:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:coordinator];
}];
managedObjectContext = moc;
}
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)
{
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"PageFlipper" 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:#"PageFlipper.sqlite"];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSPersistentStoreCoordinator* psc = persistentStoreCoordinator;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSFileManager *fileManager = [NSFileManager defaultManager];
// Migrate datamodel
NSDictionary *options = nil;
// this needs to match the entitlements and provisioning profile
NSURL *cloudURL = [fileManager URLForUbiquityContainerIdentifier:#"G88FQ4WK29.com.brandonsdesigngroup.3Doodles"];
NSString* coreDataCloudContent = [[cloudURL path] stringByAppendingPathComponent:#"data"];
if ([coreDataCloudContent length] != 0) {
// iCloud is available
cloudURL = [NSURL fileURLWithPath:coreDataCloudContent];
options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
#"3Doodles.store", NSPersistentStoreUbiquitousContentNameKey,
cloudURL, NSPersistentStoreUbiquitousContentURLKey,
nil];
} else {
// iCloud is not available
options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
}
NSError *error = nil;
[psc lock];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[psc unlock];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"asynchronously added persistent store!");
[[NSNotificationCenter defaultCenter] postNotificationName:#"RefetchAllDatabaseData" object:self userInfo:nil];
});
});
return persistentStoreCoordinator;
}
- (void)mergeiCloudChanges:(NSNotification*)note forContext:(NSManagedObjectContext*)moc {
[moc mergeChangesFromContextDidSaveNotification:note];
NSNotification* refreshNotification = [NSNotification notificationWithName:#"RefreshAllViews" object:self userInfo:[note userInfo]];
[[NSNotificationCenter defaultCenter] postNotification:refreshNotification];
}
- (void)mergeChangesFrom_iCloud:(NSNotification *)notification {
NSManagedObjectContext* moc = [self managedObjectContext];
// this only works if you used NSMainQueueConcurrencyType
// otherwise use a dispatch_async back to the main thread yourself
[moc performBlock:^{
[self mergeiCloudChanges:notification forContext:moc];
}];
}
#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
viewController.h
#import <Foundation/Foundation.h>
#import "CollectionViewController.h"
#import "SlideShowViewController.h"
#import "PagesDataSource.h"
#import "PageView.h"
#import "PageViewController.h"
#import "PrototypeView.h"
#import "QuickStart.h"
#interface PagesCollectionViewController : CollectionViewController<quickStartDismiss,NSFetchedResultsControllerDelegate>
{
PagesDataSource *dataSource;
PageViewController *viewController;
#private NSFetchedResultsController *fetchedResultsController__ ;
#private NSManagedObjectContext *managedObjectContext__;
}
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
- (id)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext;
- (IBAction)add:(id)sender;
-(void)setShadowAndColor;
-(void)playSlideShow;
#property (nonatomic, readwrite, assign) BOOL editMode;
#end
#interface PageView (CollectionViewItem)
- (void)setRepresentedObject:(PVPage *)representedObject;
- (PVPage *)representedObject;
-(void)didHoldItem;
-(void)duplicatePage;
#end
#interface PushController : UIViewController
{}
#end
#interface toolBar : UIToolbar
#end
viewController.m
#import "PagesCollectionViewController.h"
#import "PageFlipperAppDelegate.h"
#implementation toolBar
- (void)drawRect:(CGRect)rect {}
#end
#implementation PagesCollectionViewController
#synthesize editMode;
#synthesize fetchedResultsController=__fetchedResultsController;
#synthesize managedObjectContext=__managedObjectContext;
-(void)viewWillAppear:(BOOL)animated{
if (![[NSUserDefaults standardUserDefaults] integerForKey:#"integerKey"]) {
[[NSUserDefaults standardUserDefaults] setInteger:1 forKey:#"integerKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
QuickStart*stickieViewController = [[[QuickStart alloc]init]autorelease];
stickieViewController.delegate = self;
stickieViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:stickieViewController animated:YES];
}
[[self navigationController] setNavigationBarHidden:NO animated:NO];
[[self navigationController] setToolbarHidden:NO animated:NO];
[[[self navigationController] toolbar] setBarStyle:UIBarStyleBlackTranslucent];
[self setToolbarItems:[NSArray arrayWithObjects:
[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease],
[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemPlay target:self action:#selector(playSlideShow)]autorelease],
[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease],
nil]];
[(CollectionView*)[self view] setCanReloadData:YES];
[(CollectionView*)[self view]layoutSubviews];
}
- (NSFetchedResultsController *)fetchedResultsController
{
if (__fetchedResultsController != nil)
{
return __fetchedResultsController;
}
/*
Set up the fetched results controller.
*/
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Page" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptorName = [[NSSortDescriptor alloc] initWithKey:#"<sort key>" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptorName, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:#"<section name key path>" cacheName:#"<cache name>"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptorName release];
[sortDescriptors release];
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __fetchedResultsController;
}
// because the app delegate now loads the NSPersistentStore into the NSPersistentStoreCoordinator asynchronously
// we will see the NSManagedObjectContext set up before any persistent stores are registered
// we will need to fetch again after the persistent store is loaded
- (void)reloadFetchedResults:(NSNotification*)note {
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
if (note) {
[(CollectionView*)[self view] setCanReloadData:YES];
[(CollectionView*)[self view]layoutSubviews];
}
}
-(void) playSlideShow{
SlideShowViewController *slideShowViewController = [[[SlideShowViewController alloc] init]autorelease];
NSMutableArray *tempArrayOfImages = [[[NSMutableArray alloc] init]autorelease];
for (int i = 0; i < [[dataSource pages]count]; i++) {
if ([[[dataSource pages] objectAtIndex:i] thumbnail] != nil) {
[tempArrayOfImages addObject: [[[dataSource pages] objectAtIndex:i] thumbnail]];
}
}
[[self navigationController] pushViewController:slideShowViewController animated:YES];
[slideShowViewController setImagesInImageViewer:tempArrayOfImages];
}
-(void)dismissQuickStart{
[self dismissModalViewControllerAnimated:YES];
}
- (id)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
{
if ((self = [super initWithNibName:#"CollectionView" bundle:nil]))
{
if (editMode == NO) {
[self finishEditToolBars];
}
[self setTitle:#"Doodles"];
viewController = [[PageViewController alloc] initWithManagedObjectContext:managedObjectContext];
dataSource = [[PagesDataSource alloc] initWithManagedObjectContext:managedObjectContext];
CGSize itemViewMarginSize = CGSizeMake(25.0, 0.0);
[(CollectionView *)[self view] setItemViewMarginSize:itemViewMarginSize];
PrototypeView *pro = [[[PrototypeView alloc] init] autorelease];
[(CollectionView *)[self view] setItemViewPrototype:pro];
[(CollectionView *)[self view] setFlowDirection:CVFlowDirectionVertical];
[(CollectionView *)[self view] setItemViewFrameSize:CGSizeMake(([(CollectionView *)[self view] bounds].size.width - 3*itemViewMarginSize.width)/3.4, ([(CollectionView *)[self view] bounds].size.height - 3*itemViewMarginSize.height)/3.6)];
[self setShadowAndColor];
}
return self;
}
-(void)setShadowAndColor{
CollectionView *collectionView = (CollectionView *)[self view];
[collectionView setShadowColor:[UIColor blackColor]];
[collectionView setShadowRadius:6.0f];
[collectionView setShadowOpacity:0.5f];
}
- (void)add:(id)sender
{
[dataSource add:sender];
CollectionView *collectionView = (CollectionView *)[self view];
// [collectionView reloadData];
// [collectionView scrollItemIndexToVisible:[self countOfItemsInCollectionView:collectionView]-1 animated:NO];
[collectionView.dataDelegate collectionView:collectionView didSelectItemAtIndex:[self countOfItemsInCollectionView:collectionView]-1];
//CollectionViewController *c;
// [[c transitionToDetailViewController:[c collectionView:self detailViewControllerForItemAtIndex:(NSUInteger)[self countOfItemsInCollectionView:collectionView]-1] forItemView:[itemViews objectForKey:[NSString stringWithFormat:#"%u", [self countOfItemsInCollectionView:collectionView]-1]]]];
// [c transitionToDetailViewController:self forItemView:collectionView.itemViews;
editMode = NO;
//collectionView.canUpdateLayout = YES;
collectionView.canReloadData = YES;
[(CollectionView*)[self view]layoutSubviews];
}
- (NSUInteger)countOfItemsInCollectionView:(CollectionView *)collectionView { return [[dataSource pages] count]; }
- (id)collectionView:(CollectionView *)collectionView representedObjectAtIndex:(NSUInteger)itemIndex {
return [[dataSource pages] objectAtIndex:itemIndex];
}
- (void)collectionView:(CollectionView *)collectionView didSelectItemAtIndex:(NSUInteger)itemIndex
{
if (editMode == YES) {
[collectionView yellowdidSelectItemAtIndex:itemIndex];
// NSLog(#"edit");
}else{
PVPage *selectedPage = [[[dataSource pages] objectAtIndex:itemIndex]autorelease];
PageView *pageView = [[[PageView alloc] init] autorelease];
[pageView setRepresentedPage:selectedPage];
// UIImage *i = [UIImage imageWithData: [[pageView representedPage] thumbnail]];
// UIImageView *ii = [[[UIImageView alloc] initWithImage:i]autorelease];
[viewController setView:pageView];
// [(PageView*)[viewController view] setBackgroundStrokes:ii];
//NSLog(#"selected page %#",selectedPage);
// [[[self navigationController] toolbar] setHidden:YES];
// [[[self navigationController] navigationBar] setHidden:YES];
// [[[self tabBarController] tabBar] setHidden:YES];
PageFlipperAppDelegate *appDelegate = (PageFlipperAppDelegate *)[[UIApplication sharedApplication] delegate];
// [(UiWindowSubclass *)appDelegate.window startTimer];
[(UINavigationController *)[(UiWindowSubclass*)[appDelegate window] rootViewController] pushViewController:viewController animated:YES];
// viewController = nil;
// [[self navigationController] setToolbarHidden:NO];
}
}
- (BOOL)collectionView:(CollectionView *)collectionView canDeleteItemAtIndex:(NSUInteger)itemIndex {
NSLog(#"itemIndex %u",itemIndex);
return YES;
}
- (void)collectionView:(CollectionView *)collectionView didDeleteItemAtIndex:(NSUInteger)itemIndex
{
[dataSource removePageAtIndex:itemIndex];
}
-(void)trash{
// NSLog(#"trash");
[(CollectionView *)[self view] trashitems];
}
-(void)done{
[(CollectionView *)[self view] yellowdidSelectItemAtIndexUndo];
[(CollectionView *)[self view] shakedidRemoveSelectItemAtIndex];
[(CollectionView *)[self view] donereset];
[self finishEditToolBars];
}
-(void) finishEditToolBars{
[[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(add:)] autorelease]];
[[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(didHoldItem)] autorelease]];
editMode = NO;
}
-(void)duplicatePage{
NSArray *tempArray = [[[(CollectionView*)[self view] selectedItemsArray]copy]autorelease];
// for (int i =0; i<[[(CollectionView*)[self view] selectedItemsArray]count]; i++) {
// [(CollectionView *)[self view] yellowdidSelectItemAtIndex:i];
//
// }
[dataSource duplicatePage:[[[NSArray alloc] initWithArray:tempArray]autorelease]];
CollectionView *collectionView = (CollectionView *)[self view];
editMode = NO;
[self done];
// [(CollectionView *)[self view] yellowdidSelectItemAtIndexUndo];
collectionView.canReloadData = YES;
[collectionView layoutSubviews];
}
-(void)didHoldItem{
[[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(done)] autorelease]];
// [[self navigationItem] setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:#selector(trash)] autorelease]];
toolBar* tools = [[toolBar alloc] initWithFrame:CGRectMake(0, 0, 133, 44.01)];
tools.barStyle = UIBarStyleBlackTranslucent;
tools.opaque = NO;
//tools.backgroundColor = [UIColor clearColor];
// create the array to hold the buttons, which then gets added to the toolbar
NSMutableArray* buttons = [[NSMutableArray alloc] initWithCapacity:3];
// create a standard "add" button
UIBarButtonItem* bi = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:#selector(trash)];
bi.style = UIBarButtonItemStyleBordered;
[buttons addObject:bi];
[bi release];
// create a spacer
bi = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
[buttons addObject:bi];
[bi release];
// create a standard "refresh" button
bi = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemOrganize target:self action:#selector(duplicatePage)];
bi.style = UIBarButtonItemStyleBordered;
[buttons addObject:bi];
[bi release];
// stick the buttons in the toolbar
[tools setItems:buttons animated:NO];
[buttons release];
// and put the toolbar in the nav bar
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:tools] autorelease];
[tools release];
[(CollectionView*)[self view] setOldItemIndex:-1];
editMode = YES;
[(CollectionView*)[self view] setEditMode:YES];
[(CollectionView*)[self view] shakedidSelectItemAtIndex];
}
-(void)didReceiveMemoryWarning{
// NSLog(#"mem");
}
- (void)dealloc
{ [dataSource release],dataSource = nil;
[viewController release],viewController = nil;
[super dealloc];
}
-(void)viewDidAppear:(BOOL)animated{
[ (CollectionView*) [self view] setCanReloadData:YES];
[(CollectionView*) [self view] layoutSubviews];
}
-(void) viewDidLoad{
CollectionView *collectionView = (CollectionView *)[self view];
collectionView.canReloadData = YES;
[(CollectionView*)[self view]layoutSubviews];
editMode = NO;
collectionView.editMode = NO;
}
#end

On the Apple developer forums the iPhoneCoreDataRecipes sample code is posted, which includes iCloud.
https://devforums.apple.com/thread/126670?tstart=0

You can watch this year's WWDC 2012 Session 227 lecture (you can freely access these videos using your Apple Developer account), that will show how to correctly use Core Data and iCloud together, illustrating the correct application architecture, the way Core Data and iCloud should talk to each other and explaining all this stuff through a complete sample project.
Edit
The full source of the project is only available to all registered Apple developers under this page.

This is a very controversial topic... I need to add iCloud with Core Data in my next application but it's a bit hard to start. I have done nothing but I found these documents very useful:
Using Core Data with iCloud Release Notes
Using iCloud in Conjunction with Databases
Your Third iOS App: iCloud

It's not just controversial, it's not working adequately yet. If you are able to code the sample, you'll likely find that it only works on occasion. I wish I could write that it's solved and here is how you use it - maybe someone else can, but as of March 2012, I doubt it.
Still, it's interesting and instructive to code the sample, and the others in the dev site, so that you can learn what iCloud/core data is all about.
A lot of us are chomping at the bit for this to solidify.
You may want to try Dox from Ray Wenderlich's fantastic site. But you'll likely end up with the same frustration. Sometimes it works, mostly not.

Blackpixel have upped a version of Core Data Recipes with iCloud to Github. It may have improvements over the version in the dev forums.
I've used the dev forums version and found that it works, but takes some time to sync. Read the comments thread there (19 pages and counting) and make up your mind about it.

Related

UITableView Crashing

I have a UITableView I add as a subview of self.view and it crashes at
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Here is my code:
interface (in CRFeedViewController.m)
#property (assign) BOOL dataIsLoaded;
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(dataIsLoaded == YES)
{
return [self.items count];
}
else {
return 1;
}
}
// Return a cell for the index path
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Cell label
cell.textLabel.text = #"Tweet";
if (cell == nil) {
cell = [[UITableViewCell alloc] init];
}
return cell;
}
- (void)getTimeLine {
ACAccountStore *account = [[ACAccountStore alloc] init];
ACAccountType *accountType = [account accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[account requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error)
{
if (granted == YES)
{
NSArray *arrayOfAccounts = [account accountsWithAccountType:accountType];
if ([arrayOfAccounts count] > 0)
{
ACAccount *twitterAccount = [arrayOfAccounts lastObject];
NSURL *requestURL = [NSURL URLWithString:#"http://api.twitter.com/1/statuses/home_timeline.json"];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setObject:#"20" forKey:#"count"];
[parameters setObject:#"1" forKey:#"include_entities"];
SLRequest *postRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:requestURL parameters:parameters];
postRequest.account = twitterAccount;
[postRequest performRequestWithHandler: ^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
self.items = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];
if (self.items.count != 0) {
dataIsLoaded = YES;
[self.tableView reloadData];
}
else {
NSLog(#"No items");
}
}];
}
} else {
NSLog(#"No access");
}
}];
}
- (void) viewWillAppear:(BOOL)animated
{
[self getTimeLine];
}
- (void)viewDidLoad
{
[super viewDidLoad];
/**
* TABLE VIEW
* Add subview of the table
*/
self.items = [NSArray arrayWithObjects:#"test", nil];
CGRect tableViewRect = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
UITableView *tableView = [[UITableView alloc] initWithFrame:tableViewRect style:UITableViewStylePlain];
tableView.dataSource = self;
[self.view addSubview:tableView];
}
EDIT
Here is my complete code, I'm sorry I don't understand all of this yet, I am still very new.
.h
//
// CRFeedViewController.h
// Twitter
//
// Created by Cody Robertson on 6/27/13.
// Copyright (c) 2013 Cody Robertson. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <Accounts/Accounts.h>
#import <Social/Social.h>
#interface CRFeedViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (strong, nonatomic) UITableView *tableView;
#property (strong, nonatomic) NSArray *items;
#end
.m
//
// CRFeedViewController.m
// Twitter
//
// Created by Cody Robertson on 6/27/13.
// Copyright (c) 2013 Cody Robertson. All rights reserved.
//
#import "CRFeedViewController.h"
#import "CRComposeViewController.h"
#import "CRSearchViewController.h"
#interface CRFeedViewController ()
#property (assign) BOOL dataIsLoaded;
- (void) composeTweet: (id) sender;
- (void) searchTweets: (id) sender;
- (void) getTimeLine;
#end
#implementation CRFeedViewController
#synthesize dataIsLoaded;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
/**
* NAV BAR
* Add icon and button to nav bar
*/
// Add Twitter Icon as Title
UIImageView *UINavTitleLogo = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"UINavBarLogo.png"]];
UINavTitleLogo.contentMode = UIViewContentModeScaleAspectFill;
self.navigationItem.titleView = UINavTitleLogo;
// Add Search & Compose Icon
UIImage *UISearchNavButton = [UIImage imageNamed:#"Search.png"];
UIBarButtonItem *CRSearchNavButton = [[UIBarButtonItem alloc] initWithImage:UISearchNavButton style:UIBarButtonItemStylePlain target:self action:#selector(searchTweets:)];
UIImage *UIComposeNavButton = [UIImage imageNamed:#"Compose.png"];
UIBarButtonItem *CRComposeNavButton = [[UIBarButtonItem alloc] initWithImage:UIComposeNavButton style:UIBarButtonItemStylePlain target:self action:#selector(composeTweet:)];
NSArray *UINavItems = #[CRComposeNavButton, CRSearchNavButton];
self.navigationItem.rightBarButtonItems = UINavItems;
[[UINavigationBar appearance] setTitleTextAttributes:#{
UITextAttributeTextColor: [UIColor whiteColor]
}];
/**
* TAB BAR
* Add icon and label to task bar
*/
UIImage *CRFeedTabBarIcon = [UIImage imageNamed:#"Home.png"];
UITabBarItem *CRFeedTabBarItem = [[UITabBarItem alloc] initWithTitle:#"Home" image:CRFeedTabBarIcon tag:0];
self.tabBarItem = CRFeedTabBarItem;
}
return self;
}
- (void) composeTweet:(id)sender
{
/**
* PUSH VIEW TO COMPOSE
* Load the compose view
*/
CRComposeViewController *CRCompose = [[CRComposeViewController alloc] init];
CRCompose.title = #"New Tweet";
[self.navigationController pushViewController:CRCompose animated:YES];
}
- (void) searchTweets:(id)sender
{
/**
* PUSH VIEW TO SEARCH
* Load the search view
*/
CRSearchViewController *CRSearch = [[CRSearchViewController alloc] init];
CRSearch.title = #"Search";
[self.navigationController pushViewController:CRSearch animated:YES];
}
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(dataIsLoaded == YES)
{
return [self.items count];
}
else {
return 1;
}
}
// Return a cell for the index path
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Cell label
cell.textLabel.text = #"Tweet";
if (cell == nil) {
cell = [[UITableViewCell alloc] init];
}
return cell;
}
- (void)getTimeLine {
ACAccountStore *account = [[ACAccountStore alloc] init];
ACAccountType *accountType = [account accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
[account requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error)
{
if (granted == YES)
{
NSArray *arrayOfAccounts = [account accountsWithAccountType:accountType];
if ([arrayOfAccounts count] > 0)
{
ACAccount *twitterAccount = [arrayOfAccounts lastObject];
NSURL *requestURL = [NSURL URLWithString:#"http://api.twitter.com/1/statuses/home_timeline.json"];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setObject:#"20" forKey:#"count"];
[parameters setObject:#"1" forKey:#"include_entities"];
SLRequest *postRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:requestURL parameters:parameters];
postRequest.account = twitterAccount;
[postRequest performRequestWithHandler: ^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error)
{
self.items = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];
if (self.items.count != 0) {
dataIsLoaded = YES;
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}
else {
NSLog(#"No items");
}
}];
}
} else {
NSLog(#"No access");
}
}];
}
- (void) viewWillAppear:(BOOL)animated
{
[self getTimeLine];
}
- (void)viewDidLoad
{
[super viewDidLoad];
/**
* TABLE VIEW
* Add subview of the table
*/
self.items = [NSArray arrayWithObjects:#"test", nil];
CGRect tableViewRect = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
UITableView *tableView = [[UITableView alloc] initWithFrame:tableViewRect style:UITableViewStylePlain];
tableView.delegate = self;
tableView.dataSource = self;
[self.view addSubview:tableView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
You should call the reloadData method on the main thread:
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
Not sure if this is causing your crash, but you need to init your cells with the reuse identifier:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier;
I would recommend that you post the trace logged in Xcode when the app crashes. It will give a better understanding as to why your app is crashing.
Add the delegate first so those methods are ran. Don't forget to subscribe to the delegate in your .h as well.
ViewController.h
#interface ViewController : UIViewController <UITableViewDelegate,UITableViewDataSource>
#property (nonatomic, strong) NSArray *items;
// In your viewDidLoad
tableView.dataSource = self;
tableView.delegate = self;
You return 1 cell even if you don't have data. You should return 0
If the error is happening in the numberOfRows method, then the culprit is most likely:
[self.items count];
The most likely case this causes an error is if self.items does not have a count method. In your viewDidLoad, you set it to an NSArray, which does have a count method. However, there is one other place you set self.items:
self.items = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];
The result of that method most likely does not have a count method, and therefore is not an NSArray, yet you are storing it in a variable that is defined as NSArray.
After that line, above, put the following code:
NSLog(#"Class: %#", NSStringFromClass([self.items class]));
If the output is not NSArray, you most likely have a programming error.
Also, it looks like you are using multiple threads, to read/write to the same variable. This is usually not a good idea without implementing some sort of thread safety on those properties.

Code works fine on iOS5 but not on iOS4.3

I have code that works fine on iOS5 but does not work on iOS4.3, I'm trying to display a loading screen with a progress bar from a navigation controller that has a UIViewController as the root view.
The problem is that on iOS4.3 the loading screen doesn't appear at the right time, it appears just before the view of the second view controller is displayed and then disappears quickly.
Here's the code :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
NSUserDefaults * standardUserDefaults = [NSUserDefaults standardUserDefaults];
CGSize s = [[UIScreen mainScreen] bounds].size;
[standardUserDefaults setObject:#"" forKey:#"display_resolution"];
if((int)s.width == 640 && (int)s.height == 960)[standardUserDefaults setObject:#"#2x" forKey:#"display_resolution"];
[standardUserDefaults synchronize];
AC_Loading *loading = [[[AC_Loading alloc] initWithNibName:#"AC_Loading_iPhone" bundle:nil] autorelease];
_navController0 = [[[UINavigationController alloc]initWithRootViewController:loading]autorelease];
_navController0.navigationBar.hidden = YES;
self.window.rootViewController = self.navController0;
[self.window makeKeyAndVisible];
return YES;
}
-
Edit
I figured out that the problem came from AC_Loading's code, this UIViewController has to display a loading screen with a progress view that updates according to database stat (I'm creating a sqlite3 database and updating it if needed and showing progress).While using this code on iOS5 works but it doesn't on iOS4.x I thought is because of the loop inside viewDidAppear (While pr<1.0):
#import "AC_Loading.h"
#import "database.h"
#import "AC_Menu.h"
#implementation AC_Loading
#synthesize logo;
#synthesize progress;
#synthesize informations;
#synthesize CLController;
float pr = 0.14;
int p = 0;
AC_Menu *menu;
NSUserDefaults *standardUserDefaults;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)viewDidLoad
{
[super viewDidLoad];
standardUserDefaults = [NSUserDefaults standardUserDefaults];
[standardUserDefaults setObject:#"NO" forKey:#"geoloc"];
[standardUserDefaults synchronize];
NSLog(#"%#", [NSString stringWithFormat:#"intro%#%#", [standardUserDefaults stringForKey:#"display_resolution"], #".jpg"]);
[logo setImage:[UIImage imageNamed:[NSString stringWithFormat:#"intro%#%#", [standardUserDefaults stringForKey:#"display_resolution"], #".jpg"]]];
//[progress setProgressTintColor:[UIColor purpleColor]];
[progress setProgress:0.14];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[self setLogo:nil];
[self setInformations:nil];
[self setProgress:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:YES];
database *DB = [[database alloc] init];
[DB checkDB];
NSString *message = #"Chargement des données";
if([DB isCreated]== NO && [DB upToDate] == NO && sqlite3_open([[DB getDBPath:[NSString stringWithFormat:#"%#%#%#", #"Restaurant_V", [DB getVersion], #".sqlite" ]] UTF8String], [DB getDB]) == SQLITE_OK)
{
message = #"Mise à jour des données";
[DB setExecuting:YES];
[NSThread detachNewThreadSelector:#selector(createDB) toTarget:DB withObject:nil];
while([DB isExecuting]==YES)
{
if([DB isExecuting]==NO) break;
}
NSLog(#"Cas 1");
}
if([DB isCreated]== YES && [DB upToDate] == NO && sqlite3_open([[DB getDBPath:[NSString stringWithFormat:#"%#%#%#", #"Restaurant_V", [DB getVersion], #".sqlite" ]] UTF8String], [DB getDB]) == SQLITE_OK)
{
[DB setExecuting:YES];
[NSThread detachNewThreadSelector:#selector(updateDB:) toTarget:DB withObject:[DB getVersion]];
while([DB isExecuting]==YES)
{
if([DB isExecuting]==NO) break;
}
NSLog(#"Cas 2");
}
int p = floor([progress progress]*100);
while (pr<1.0)
{
p = floor(pr*100);
if(p%14==0)
{
CFRunLoopRunInMode (kCFRunLoopDefaultMode, 0, true);
[progress setProgress:pr];
[informations setText:[NSString stringWithFormat:#"%# (%d%#", message, p, #"%)"]];
}
pr += 0.000002;
}
[progress setProgress:1.0];
[informations setText:[NSString stringWithFormat:#"%# (100%#", message, #"%)"]];
menu =
[[[AC_Menu alloc] initWithNibName:#"AC_Menu_iPhone" bundle:nil] autorelease];
[self.navigationController pushViewController:menu animated:YES];
[DB release];
CLController = [[CoreLocationController alloc] init];
CLController.delegate = self;
[CLController.locMgr startUpdatingLocation];
}
- (void)dealloc {
[CLController release];
[logo release];
[informations release];
[progress release];
[super dealloc];
}

Possible memory leak

I know this is a very stupid question to ask but i have a view controller which has a mapview in it and some uibuttons i have done every thng to eliminate all the leaks bt still after 2-3 toggle between two controller app crashs. Below is the code for allocation and dellocation. BTW i dont get any "did recive memoru warning".. Thnx alot
.h/
#interface MapView : BaseViewController <MKMapViewDelegate,MKAnnotation> {
MKMapView *mapView;
NSMutableArray *placeName;
NSString *mid;
UISegmentedControl *segmentedControl;
IBOutlet UILabel *numberofbeeps;
NSInteger badgenumber;
}
#property (nonatomic, retain) UILabel *numberofbeeps;
#property(nonatomic, retain) NSString *mid;
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
#property(nonatomic,retain) NSMutableArray *placeName;
#property (nonatomic,retain) IBOutlet UISegmentedControl *segmentedControl;
-(IBAction)refreshButtonPressed:(id)sender;
-(IBAction) segmentedControlIndexChanged;
-(IBAction)SignUpButtonPressed:(id)sender;
-(IBAction)BackButtonPressed:(id)sender;
-(IBAction)AddBeepButtonPressed:(id)sender;
-(id)initWithAnnotation:(id ) annotation;
-(IBAction)sliderChanged:(id)sender;
-(IBAction)MyAccountPageButtonPressed:(id)sender;
-(IBAction)MyBeepsButtonPressed:(id)sender;
#end
.m/
-(void)network:(WNetwork*)network didFinishLoadingWithRequest:(NSInteger)pReq data:(NSMutableDictionary*)pData
{
[self removeLoader];
switch (pReq) {
case JBJsonParser:
{
NSMutableArray *array = [NSMutableArray new];
self.placeName = array;
[array release];
self.placeName = pData;
badgenumber = [placeName count];
NSString *checkstring = [[AppHelper mDataManager] objectForKey:#"numberofbeepsnearby"];
NSInteger check = [checkstring intValue];
switch (check) {
case 0:
{
self.numberofbeeps.text =[NSString stringWithFormat:#"No beeps found nearby. Why not beep something?"];
NSLog(#"%#",checkstring);
}
break;
case 1:
{
self.numberofbeeps.text =[NSString stringWithFormat:#"%# beep found nearby! %d beeps worldwide.",checkstring,badgenumber];
NSLog(#"%#",checkstring);
}
break;
default:
{
self.numberofbeeps.text =[NSString stringWithFormat:#"%# beeps found nearby! %d beeps worldwide.",checkstring,badgenumber];
NSLog(#"%#",checkstring);
}
break;
}
if ([placeName count])
{
for (int i =0; i < [placeName count]; i++)
{
NSDictionary *dict = [placeName objectAtIndex:i];
CLLocationCoordinate2D coordinatemain;
coordinatemain.latitude = [[dict objectForKey:#"Lat"] doubleValue];
coordinatemain.longitude = [[dict objectForKey:#"long"] doubleValue];
DLog(#"id of Beeps %#", mid);
NSString *username = [NSString stringWithFormat:#"by %#",[dict objectForKey:#"username"]];
MyAnnotation *ann = [[MyAnnotation alloc] init];
ann.title = [dict objectForKey:#"beep"];
ann.subtitle = username;
ann.beepid=[dict objectForKey:#"beepid"];
ann.coordinate = coordinatemain;
ann.coordinate.latitude == [[dict objectForKey:#"Lat"] doubleValue];
ann.coordinate.longitude == [[dict objectForKey:#"long"] doubleValue];
[mapView addAnnotation:ann];
[ann release];
}
}
}
break;
default:
break;
}
}
-(IBAction) segmentedControlIndexChanged{
switch (self.segmentedControl.selectedSegmentIndex) {
case 0:
{
Screen1 *objCont = [[Screen1 alloc] initWithNibName:#"Screen1" bundle:nil];
objCont.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController: objCont animated: YES];
[objCont release];
}
break;
case 1:
{
MapView *objCont = [[MapView alloc] initWithNibName:#"MapView" bundle:nil];
objCont.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController: objCont animated: YES];
[objCont release];
}
break;
default:
break;
}
}
#pragma mark -
#pragma mark request delegates
-(void)makeAccomodationRequest
{
NSMutableDictionary *paramDic = [[NSMutableDictionary alloc] init];
[self.mWNetowrk makeRequsetWithURL:URL_Showbeepsmap type:JBJsonParser paramDictionary:paramDic delegate:self];
[paramDic autorelease];
}
-(BOOL)network:(WNetwork*)network shouldStartForRequest:(NSInteger)pReq
{
[self addLoaderWithtext:#"Loading"];
return YES;
}
-(void)network:(WNetwork*)network didFailForRequest:(NSInteger)pReq WithError:(NSString*)error
{
[AppHelper showAlert:error];
[self removeLoader];
}
-(void)initializeView
{
[self initializeOutlets];
[self makeAccomodationRequest];
}
-(void)initializeOutlets
{
}
-(IBAction)BackButtonPressed:(id)sender
{
Screen1 *objCont = [[Screen1 alloc] initWithNibName:#"Screen1" bundle:nil];
objCont.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController: objCont animated: YES];
[objCont release];
}
-(IBAction)refreshButtonPressed:(id)sender
{
MapView *objCont = [[MapView alloc] initWithNibName:#"MapView" bundle:nil];
objCont.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController: objCont animated: YES];
[objCont release];
}
-(IBAction)MyAccountPageButtonPressed:(id)sender
{
NSString *sid = [[AppHelper mDataManager] objectForKey:#"logout"];
{
NSDecimalNumber *session = [[AppHelper mDataManager] objectForKey:#"sid"];
if ([sid isEqualToString:#"logged out"]||session==NULL) {
AddPlace *objCont = [[AddPlace alloc] initWithNibName:#"AddPlace" bundle:nil];
objCont.modalTransitionStyle = UIModalTransitionStyleCrossDissolve ;
[self presentModalViewController: objCont animated: YES];
[objCont release];
}
else {
MyAccountPage *objCont = [[MyAccountPage alloc] initWithNibName:#"MyAccountPage" bundle:nil];
objCont.modalTransitionStyle = UIModalTransitionStyleCrossDissolve ;
[self presentModalViewController: objCont animated: YES];
[objCont release];
}
}
}
-(IBAction)MyBeepsButtonPressed:(id)sender
{
NSString *sid = [[AppHelper mDataManager] objectForKey:#"logout"];
NSDecimalNumber *session = [[AppHelper mDataManager] objectForKey:#"sid"];
//NSString *sessionStr = [session stringValue];
if ([sid isEqualToString:#"logged out"]||session==NULL) {
[[AppHelper mDataManager] setValue:#"MyBeeps" forKey:#"appflow"];
AddPlace *objCont = [[AddPlace alloc] initWithNibName:#"AddPlace" bundle:nil];
objCont.modalTransitionStyle = UIModalTransitionStyleCrossDissolve ;
[self presentModalViewController: objCont animated: YES];
[objCont release];
}
else {
MyBeeps1 *objCont = [[MyBeeps1 alloc] initWithNibName:#"MyBeeps1" bundle:nil];
objCont.modalTransitionStyle = UIModalTransitionStyleCrossDissolve ;
[self presentModalViewController: objCont animated: YES];
[objCont release];
}
}
-(IBAction)AddBeepButtonPressed:(id)sender
{
NSString *sid = [[AppHelper mDataManager] objectForKey:#"logout"];
NSDecimalNumber *session = [[AppHelper mDataManager] objectForKey:#"sid"];
if([sid isEqualToString:#"logged out"]||session==NULL) {
[[AppHelper mDataManager] setValue:#"Addabeep" forKey:#"appflow"];
AddPlace *objCont = [[AddPlace alloc] initWithNibName:#"AddPlace" bundle:nil];
objCont.modalTransitionStyle = UIModalTransitionStyleCrossDissolve ;
[self presentModalViewController: objCont animated: YES];
[objCont release];
}
else {
[[AppHelper mDataManager] setValue:#"Addabeep" forKey:#"appflow"];
Check20M *objCont = [[Check20M alloc] initWithNibName:#"Check20M" bundle:nil];
objCont.modalTransitionStyle = UIModalTransitionStyleCrossDissolve ;
[self presentModalViewController: objCont animated: YES];
[objCont release];
}
}
#pragma mark -
#pragma mark MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if (annotation == mapView.userLocation) {
// NSLog(#"nil");
return nil; }
MKPinAnnotationView *pinView = nil;
static NSString *defaultPinID = #"com.invasivecode.pin";
pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
pinView.pinColor = MKPinAnnotationColorGreen;
pinView.frame=CGRectMake(0, 0, 30, 30);
pinView.canShowCallout = YES;
pinView.animatesDrop = YES;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
MyAnnotation *temp = (MyAnnotation*)annotation;
infoButton.tag = [temp.beepid integerValue];
[infoButton addTarget:self action:#selector(showDetails:) forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = infoButton;
[defaultPinID release];
return pinView;
}
-(IBAction)showDetails:(id)sender{
UIButton *button = (UIButton*)sender ;
NSLog(#"Annotation Click");
BeepsDetail *objCont = [[BeepsDetail alloc] initWithNibName:#"BeepsDetail" bundle:nil];
objCont.mId = [NSString stringWithFormat:#"%d",button.tag];
objCont.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController: objCont animated: YES];
[objCont release];
}
#pragma mark -
#pragma mark mapView delegates
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
mapView.delegate = self;
[self initializeView];
mapView.showsUserLocation = YES;
[self makeAccomodationRequest];
CLLocation *location = [[AppHelper appDelegate] mLatestLocation];
MKCoordinateRegion region;
region.center.latitude = location.coordinate.latitude;
region.center.longitude = location.coordinate.longitude;
region.span.latitudeDelta = 0.001;
// Add a little extra space on the sides
region.span.longitudeDelta = 0.001;
// Add a little extra space on the sides
region = [mapView regionThatFits:region];
[mapView setRegion:region animated:YES];
}
// Listen to change in the userLocation
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.mapView = nil;
self.numberofbeeps =nil;
self.mapView = nil;
self.segmentedControl = nil;
}
- (void)dealloc
{
[mapView release];
// [self.mapView removeFromSuperview];
[placeName release];
//[mid autorelease];
[super dealloc];
}
- (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.
}
#end
The following only works on the simulator not on device...
Here is a good procedure for finding bad access errors using zombies. All the tools are built into Xcode.
First change to profiling. Click and hold one the run button.
Now choose zombies. This tool warns you just before you are about to use a deallocated object which would other wise trigger a bad access.
Now when a zombie is detected you will see something like this (minus annotatios!) using the tools you can see the object lifecycle. Double click to be taken the the code.
Hope it helps someone!
I would suggest declaring modal view controllers (objCont) as autorelease as opposed to manually releasing them.

init an array in initWithNibName

I am trying to set up an array in my UIViewController. The nib gets loaded into my app, sometimes repeatedly. I am adding this to my initWithNibName to init the array
NSMutableArray *temp = [[NSMutableArray alloc] initWithObjects:#"one",#"two",#"three",#"four",#"five",nil];
[self setScoreArray:temp];
[temp release];
scoreArray is a MutableArray with synthesized properties. When I go to access the array in viewDidLoad I get [[self scoreArray] count] as 0. Also, when I load the nib repeatedly I get a bad access error. Any suggestions? Am I missing a step. Thanks. I am synthesizing the property for the array, in my class declaration:
NSMutableArray *_scoreArray;
then
#property (nonatomic, retain) NSMutableArray *scoreArray;
then in my implementation
#synthesize scoreArray =_scoreArray;
and in my dealloc
[_scoreArray release], _scoreArray = nil;
I'm editing this post to show how I'm loading the nibs with my RootViewController
- (void) createNewSlide:(NSInteger)slideIndex {
NSDictionary *slideObj = (NSDictionary *)[[self slidesDataSource] objectAtIndex:slideIndex - 1];
NSString *currentTitle = [slideObj objectForKey:#"title"];
[[self slideTitle] setText:currentTitle];
NSString *currentContent = [slideObj objectForKey:#"contentString"];
NSString *currentContentType = [slideObj objectForKey:#"contentType"];
if ([self currentVC] != nil) {
[[self currentVC] reset];
[self setCurrentVC:nil];
}
if ([currentContentType isEqualToString:#"slide"])
{
[[self containerViewController] loadImage:currentContent];
}
else if ([currentContentType isEqualToString:#"quiz"])
{
NSInteger quizNum = [[slideObj objectForKey:#"quizNum"] integerValue];
NSLog(#"%s%#%d",__FUNCTION__,#"quizNum ",quizNum);
QuizViewController *quizView = [[QuizViewController alloc] initWithNibName:#"QuizViewController" bundle:nil];
[self setCurrentVC:quizView];
[quizView release];
[[self containerViewController] replaceSlideWithViewController:[self currentVC]];
}
else if ([currentContentType isEqualToString:#"PIDView"])
{
PIDViewController *PIDView = [[PIDViewController alloc] initWithNibName:#"PIDView" bundle:nil];
[self setCurrentVC:PIDView];
[PIDView release];
[[self containerViewController] replaceSlideWithViewController:[self currentVC]];
}
else if ([currentContentType isEqualToString:#"LoginView"])
{
LoginViewController *login = [[LoginViewController alloc] initWithNibName:#"LoginView" bundle:nil];
[self setCurrentVC:login];
[login release];
[[self containerViewController] replaceSlideWithViewController:[self currentVC]];
}
else if ([currentContentType isEqualToString:#"VakView"])
{
VakViewController *vakView = [[VakViewController alloc] initWithNibName:#"VakView" bundle:nil];
[self setCurrentVC:vakView];
[vakView release];
[[self containerViewController] replaceSlideWithViewController:[self currentVC]];
}
else if ([currentContentType isEqualToString:#"PlanView"])
{
PlanViewController *planView = [[PlanViewController alloc] initWithNibName:#"PlanView" bundle:nil];
[self setCurrentVC:planView];
[planView release];
[[self containerViewController] replaceSlideWithViewController:[self currentVC]];
}
Thanks for your insights.
PlanView is the one that causes the problem. But it is not when it loads, it's when something else loads after it. I have run the analyzer and it reports no memory leaks.
BTW, currentVC is a synthesized property.
How is your UIViewController being created? If it is being created via another nib, then -initWithNibName:bundle: doesn't get called. Instead, -initWithCoder: and -awakeFromNib are called.

tableView:didSelectRowAtIndexPath: calls TTNavigator openURLAction:applyAnimated: — UITabBar and navigationItem disappear

I have an existing iphone project with a UITabBar. Now I need styled text and in-text links to other ViewControllers in my app. I am trying to integrate TTStyledTextLabel.
I have a FirstViewController:UITabelViewController with this tableView:didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *url;
if ([self.filteredQuestions count]>0) {
url = [NSString stringWithFormat:#"%#%d", #"tt://question/", [[self.filteredQuestions objectAtIndex:indexPath.row] id]];
[[TTNavigator navigator] openURLAction:[[TTURLAction actionWithURLPath: url] applyAnimated:YES]];
} else {
Question * q = [self.questions objectAtIndex:indexPath.row] ;
url = [NSString stringWithFormat:#"%#%d", #"tt://question/", [q.id intValue]];
}
TTDPRINT(#"%#", url);
TTNavigator *navigator = [TTNavigator navigator];
[navigator openURLAction:[[TTURLAction actionWithURLPath: url] applyAnimated:YES]];
}
My mapping looks like this:
TTNavigator* navigator = [TTNavigator navigator];
navigator.window = window;
navigator.supportsShakeToReload = YES;
TTURLMap* map = navigator.URLMap;
[map from:#"*" toViewController:[TTWebController class]];
[map from:#"tt://question/(initWithQID:)" toViewController:[QuestionDetailViewController class]];
and my QuestionDetailViewController:
#interface QuestionDetailViewController : UIViewController <UIScrollViewDelegate , QuestionDetailViewProtocol> {
Question *question;
}
#property(nonatomic,retain) Question *question;
-(id) initWithQID:(NSString *)qid;
-(void) goBack:(id)sender;
#end
When I hit a cell, q QuestionDetailViewController will be called — but the navigationBar wont
#implementation QuestionDetailViewController
#synthesize question;
-(id) initWithQID:(NSString *)qid
{
if (self = [super initWithNibName:#"QuestionDetailViewController" bundle:nil]) {
//;
TTDPRINT(#"%#", qid);
NSManagedObjectContext *managedObjectContext = [(domainAppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"id == %#", qid];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Question"
inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
if (error==nil && [array count]>0 ) {
self.question = [array objectAtIndex:0];
} else {
TTDPRINT(#"error: %#", array);
}
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[TTStyleSheet setGlobalStyleSheet:[[[TextTestStyleSheet alloc] init] autorelease]];
[self.navigationController.navigationBar setTranslucent:YES];
NSArray *includedLinks = [self.question.answer.text vs_extractExternalLinks];
NSMutableDictionary *linksToTT = [[NSMutableDictionary alloc] init];
for (NSArray *a in includedLinks) {
NSString *s = [a objectAtIndex:3];
if ([s hasPrefix:#"/answer/"] || [s hasPrefix:#"http://domain.com/answer/"] || [s hasPrefix:#"http://www.domain.com/answer/"]) {
NSString *ttAdress = #"tt://question/";
NSArray *adressComps = [s pathComponents];
for (NSString *s in adressComps) {
if ([s isEqualToString:#"qid"]) {
ttAdress = [ttAdress stringByAppendingString:[adressComps objectAtIndex:[adressComps indexOfObject:s]+1]];
}
}
[linksToTT setObject:ttAdress forKey:s];
}
}
for (NSString *k in [linksToTT allKeys]) {
self.question.answer.text = [self.question.answer.text stringByReplacingOccurrencesOfString:k withString: [linksToTT objectForKey:k]];
}
TTStyledTextLabel *answerText = [[[TTStyledTextLabel alloc] initWithFrame:CGRectMake(0, 0, 320, 700)] autorelease];
if (![[self.question.answer.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] hasPrefix:#"<div"]) {
self.question.answer.text = [NSString stringWithFormat:#"%<div>%#</div>", self.question.answer.text];
}
NSString * s = [NSString stringWithFormat:#"<div class=\"header\">%#</div>\n%#",self.question.title ,self.question.answer.text];
answerText.text = [TTStyledText textFromXHTML:s lineBreaks:YES URLs:YES];
answerText.contentInset = UIEdgeInsetsMake(20, 15, 20, 15);
[answerText sizeToFit];
[self.navigationController setNavigationBarHidden:NO animated:YES];
[self.view addSubview:answerText];
[(UIScrollView *)self.view setContentSize:answerText.frame.size];
self.view.backgroundColor = [UIColor whiteColor];
[linksToTT release];
}
.......
#end
This works quite nice, as soon as a cell is touched, a QuestionDetailViewController is called and pushed — but the tabBar will disappear, and the navigationItem — I set it like this: self.navigationItem.title =#"back to first screen"; — won't be shown. And it just appears without animation.
But if I press a link inside the TTStyledTextLabel the animation works, the navigationItem will be shown.
How can I make the animation, the navigationItem and the tabBar be shown?
I found a solution:
My QuestionDetailViewController implements the TTNavigatorDelegate.
-(BOOL)navigator:(TTNavigator *)navigator shouldOpenURL:(NSURL *)URL will always return NO, but will call [self.navigationController pushViewController:c animated:YES];
-(BOOL)navigator:(TTNavigator *)navigator shouldOpenURL:(NSURL *)URL {
NSEntityDescription *entity;
NSPredicate *predicate;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
if ([[URL host] isEqualToString:#"question"]) {
entity =[NSEntityDescription entityForName:#"Question" inManagedObjectContext:managedObjectContext];
predicate = [NSPredicate predicateWithFormat:#"id == %#", [[URL path] stringByReplacingOccurrencesOfString:#"/" withString:#""]];
[request setEntity:entity];
[request setPredicate:predicate];
NSError *error =nil;
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
if (error==nil && [array count] >0) {
QuestionDetailViewController *c = [[[QuestionDetailViewController alloc] init] autorelease];
c.question = [array objectAtIndex:0];
[self.navigationController pushViewController:c animated:YES];
}
}
[request release];
return NO;
}
In your TableViewController, add:
- (id<UITableViewDelegate>)createDelegate {
return self;
}
Then you can implement your own didSelectRowAtIndexPath and accessoryButtonTappedForRowWithIndexPath methods.