Recently modified my app to include a tab view controller. I'm now unable to load all of the categories that are in my SQLite database when the app launches and goes to the Categories table view nav controller on app load (CategoriesViewController). There are 6 category names that it should display; sometimes the app displays 0 rows, other times it displays 4. Modifying the XML file that this pulls data from, I got it to pull 6 categories (after a few times of 0 and fast execution speed). Leads me to think this has to do with timing of execution vs. time until the table view is loaded with data. Any ideas on what I need to change to get CategoriesViewController to display the table only after all data is read? Here's the code; please let me know if there's anything else that you'd need to see. Thanks!
CategoriesViewController.h
#import <UIKit/UIKit.h>
#interface CategoriesViewController : UITableViewController
#property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
- (void)fetch; // Fetches categories from data store
#end
CategoriesViewController.m
#import "CategoriesViewController.h"
#import "ProductsViewController.h"
#import "Category.h"
#import "AppDelegate.h"
#interface CategoriesViewController () // Categories View Controller interface
#property (nonatomic, strong) ProductsViewController *productController;
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
#property (weak, nonatomic) IBOutlet UIImageView *logoImageView;
#end
#pragma mark -
#implementation CategoriesViewController
- (void)viewDidLoad {
[super viewDidLoad];
_logoImageView.image = [UIImage imageNamed:#"company.jpg"];
[self fetch]; // Fetch categories from our data store
}
- (void)fetch {
NSError *error = nil;
BOOL success = [self.fetchedResultsController performFetch:&error]; // Fetch results; if error, assign error code, output message
NSAssert2(success, #"Unhandled error performing fetch at CategoriessViewController.m, line %d: %#", __LINE__, [error localizedDescription]);
}
- (NSFetchedResultsController *)fetchedResultsController {
if (_fetchedResultsController == nil) {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"Category" inManagedObjectContext:app.managedObjectContext]]; // Fetch categories
NSArray *sortDescriptors = nil;
NSString *sectionNameKeyPath = nil;
sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:#"order" ascending:YES]];
[fetchRequest setSortDescriptors:sortDescriptors];
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:app.managedObjectContext
sectionNameKeyPath:sectionNameKeyPath
cacheName:nil];
}
return _fetchedResultsController;
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)table {
return [[self.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCellIdentifier = #"CategoryCell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:kCellIdentifier forIndexPath:indexPath];
Category *category = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:NSLocalizedString(#"%#", #"%#"), category.name];
return cell;
}
// Pass managed object to ProductsViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showProducts"]) {
ProductsViewController *detailsController = (ProductsViewController *)[segue destinationViewController];
NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
detailsController.category = [self.fetchedResultsController objectAtIndexPath:selectedIndexPath];
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[[segue destinationViewController] setManagedObjectContext:app.managedObjectContext];
}
}
#end
AppDelegate.h
#import <UIKit/UIKit.h>
#import "companyXMLImporter.h"
#interface AppDelegate : NSObject <UIApplicationDelegate, companyXMLImporterDelegate>
#property (nonatomic, strong) UIWindow *window;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (NSDate *)lasModificationDateOfFileAtURL:(NSURL *)url;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "ProductsViewController.h"
#import "CategoriesViewController.h"
#interface AppDelegate()
#property (nonatomic, strong) ProductsViewController *productsViewController;
#property (nonatomic, strong) CategoriesViewController *categoriesViewController;
// Properties for the importer and its background processing
#property (nonatomic, strong) companyXMLImporter *importer;
#property (nonatomic, strong) NSOperationQueue *operationQueue;
#property (nonatomic, strong) NSString *persistentStorePath;
#end
#implementation AppDelegate
static NSString * const kLastStoreUpdateKey = #"LastStoreUpdate"; // Identifies update object in user defaults storage
static NSTimeInterval const kRefreshTimeInterval = 3600;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSDate *lastUpdate = [[NSUserDefaults standardUserDefaults] objectForKey:kLastStoreUpdateKey];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:NSLocalizedString(#"Products XML", #"Products XML")]];
NSDate *lastModifiedDate = [self lasModificationDateOfFileAtURL:url];
if (lastUpdate == nil || lastModifiedDate >= lastUpdate || -[lastUpdate timeIntervalSinceNow] > kRefreshTimeInterval) {
if ([[NSFileManager defaultManager] fileExistsAtPath:self.persistentStorePath]) {
NSError *error = nil;
BOOL oldStoreRemovalSuccess = [[NSFileManager defaultManager] removeItemAtPath:self.persistentStorePath error:&error];
NSAssert3(oldStoreRemovalSuccess, #"Unhandled error adding persistent store in %s at line %d: %#", __FUNCTION__, __LINE__, [error localizedDescription]);
}
// Object to retrieve, parse, and import into CoreData store
self.importer = [[companyXMLImporter alloc] init];
self.importer.delegate = self;
// pass coordinator so importer can create its own managed object context
self.importer.persistentStoreCoordinator = self.persistentStoreCoordinator;
// URL for products XML file
self.importer.companyURL = [NSURL URLWithString:[NSString stringWithFormat:NSLocalizedString(#"Products XML", #"Products XML")]];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[self.operationQueue addOperation:self.importer];
}
}
- (NSOperationQueue *)operationQueue {
if (_operationQueue == nil) {
_operationQueue = [[NSOperationQueue alloc] init];
}
return _operationQueue;
}
- (NSDate *)lasModificationDateOfFileAtURL:(NSURL *)url {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
// Get only header
request.HTTPMethod = #"HEAD";
NSHTTPURLResponse *response = nil;
NSError *error = nil;
[NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (error) {
NSLog(#"Error: %#", error.localizedDescription);
return nil;
} else if([response respondsToSelector:#selector(allHeaderFields)]) {
NSDictionary *headerFields = [response allHeaderFields];
NSString *lastModification = [headerFields objectForKey:#"Last-Modified"];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"EEE, dd MMM yyyy HH:mm:ss zzz"];
return [formatter dateFromString:lastModification];
}
return nil;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator == nil) {
NSURL *storeUrl = [NSURL fileURLWithPath:self.persistentStorePath];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];
NSError *error = nil;
NSPersistentStore *persistentStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error];
NSAssert3(persistentStore != nil, #"Unhandled error adding persistent store in %s at line %d: %#", __FUNCTION__, __LINE__, [error localizedDescription]);
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
if (_managedObjectContext == nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[self.managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
}
return _managedObjectContext;
}
- (NSString *)persistentStorePath {
if (_persistentStorePath == nil) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths lastObject];
_persistentStorePath = [documentsDirectory stringByAppendingPathComponent:#"Company.sqlite"];
}
return _persistentStorePath;
}
- (void)importerDidSave:(NSNotification *)saveNotification {
if ([NSThread isMainThread]) {
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
// [self.categoriesViewController fetch];
[self.productsViewController fetch];
} else {
[self performSelectorOnMainThread:#selector(importerDidSave:) withObject:saveNotification waitUntilDone:NO];
}
}
// Main-thread import completion processing
- (void)handleImportCompletion {
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:kLastStoreUpdateKey];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
self.importer = nil;
}
- (void)importerDidFinishParsingData:(companyXMLImporter *)importer {
[self performSelectorOnMainThread:#selector(handleImportCompletion) withObject:nil waitUntilDone:NO];
}
// Process errors received in delegate callback
- (void)handleImportError:(NSError *)error {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
self.importer = nil;
NSString *errorMessage = [error localizedDescription];
NSString *alertTitle = NSLocalizedString(#"Error", #"Title for alert displayed when download or parse error occurs.");
NSString *okTitle = NSLocalizedString(#"OK ", #"OK Title for alert displayed when download or parse error occurs.");
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:alertTitle
message:errorMessage
delegate:nil
cancelButtonTitle:okTitle
otherButtonTitles:nil];
[alertView show];
}
- (void)importer:(companyXMLImporter *)importer didFailWithError:(NSError *)error {
[self performSelectorOnMainThread:#selector(handleImportError:) withObject:error waitUntilDone:NO];
}
#end
companyXMLImporter.h
#import <UIKit/UIKit.h>
#import <libxml/tree.h>
#class companyXMLImporter, Product, Category, CategoryCache;
#protocol companyXMLImporterDelegate <NSObject>
#optional
- (void)importerDidSave:(NSNotification *)saveNotification; // Posted when saved
- (void)importerDidFinishParsingData:(companyXMLImporter *)importer; // Called when parsing is finished
- (void)importer:(companyXMLImporter *)importer didFailWithError:(NSError *)error; // Called if error
#end
#interface companyXMLImporter : NSOperation {
#private
id <companyXMLImporterDelegate> __unsafe_unretained delegate;
// Reference to the libxml parser context
xmlParserCtxtPtr context;
NSURLConnection *xmlConnection;
BOOL done;
BOOL parsingAProduct;
// Used for getting character data from XML elements
BOOL storingCharacters;
NSMutableData *characterBuffer;
Product *currentProduct;
NSUInteger countForCurrentBatch;
NSManagedObjectContext *insertionContext;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
NSEntityDescription *productEntityDescription;
CategoryCache *theCache;
NSURL *companyURL;
}
#property (nonatomic, retain) NSURL *companyURL;
#property (nonatomic, assign) id <companyXMLImporterDelegate> delegate;
#property (nonatomic, retain) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (nonatomic, retain, readonly) NSManagedObjectContext *insertionContext;
#property (nonatomic, retain, readonly) NSEntityDescription *productEntityDescription;
#property (nonatomic, retain, readonly) CategoryCache *theCache;
- (void)main;
#end
companyXMLImporter.m
#import "companyXMLImporter.h"
#import "Product.h"
#import "Category.h"
#import "CategoryCache.h"
#import <libxml/tree.h>
// Function prototypes for SAX callbacks
static void startElementSAX(void *context, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes);
static void endElementSAX(void *context, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI);
static void charactersFoundSAX(void *context, const xmlChar *characters, int length);
static void errorEncounteredSAX(void *context, const char *errorMessage, ...);
static xmlSAXHandler simpleSAXHandlerStruct; // Forward reference. Structure defined in full at end of file
#interface companyXMLImporter ()
#property BOOL storingCharacters;
#property (nonatomic, retain) NSMutableData *characterBuffer;
#property BOOL done;
#property BOOL parsingAProduct;
#property NSUInteger countForCurrentBatch;
#property (nonatomic, retain) Product *currentProduct;
#property (nonatomic, retain) NSURLConnection *xmlConnection;
#property (nonatomic, retain) NSDateFormatter *dateFormatter;
#end
static double lookuptime = 0;
#implementation companyXMLImporter
#synthesize companyURL, delegate, persistentStoreCoordinator;
#synthesize xmlConnection, done, parsingAProduct, storingCharacters, currentProduct, countForCurrentBatch, characterBuffer;
- (void)main {
if (delegate && [delegate respondsToSelector:#selector(importerDidSave:)]) {
[[NSNotificationCenter defaultCenter] addObserver:delegate selector:#selector(importerDidSave:) name:NSManagedObjectContextDidSaveNotification object:self.insertionContext];
}
done = NO;
self.characterBuffer = [NSMutableData data];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:companyURL];
xmlConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self]; // create connection with request and start loading data
context = xmlCreatePushParserCtxt(&simpleSAXHandlerStruct, (__bridge void *)(self), NULL, 0, NULL);
if (xmlConnection != nil) {
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);
}
// Release thread resources
xmlFreeParserCtxt(context);
self.characterBuffer = nil;
self.dateFormatter = nil;
self.xmlConnection = nil;
self.currentProduct = nil;
theCache = nil;
NSError *saveError = nil;
NSAssert1([insertionContext save:&saveError], #"Unhandled error saving managed object context in import thread: %#", [saveError localizedDescription]);
if (delegate && [delegate respondsToSelector:#selector(importerDidSave:)]) {
[[NSNotificationCenter defaultCenter] removeObserver:delegate name:NSManagedObjectContextDidSaveNotification object:self.insertionContext];
}
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(importerDidFinishParsingData:)]) {
[self.delegate importerDidFinishParsingData:self];
}
}
- (NSManagedObjectContext *)insertionContext {
if (insertionContext == nil) {
insertionContext = [[NSManagedObjectContext alloc] init];
[insertionContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
}
return insertionContext;
}
- (void)forwardError:(NSError *)error {
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(importer:didFailWithError:)]) {
[self.delegate importer:self didFailWithError:error];
}
}
- (NSEntityDescription *)productEntityDescription {
if (productEntityDescription == nil) {
productEntityDescription = [NSEntityDescription entityForName:#"Product" inManagedObjectContext:self.insertionContext];
}
return productEntityDescription;
}
- (CategoryCache *)theCache {
if (theCache == nil) {
theCache = [[CategoryCache alloc] init];
theCache.managedObjectContext = self.insertionContext;
}
return theCache;
}
- (Product *)currentProduct {
if (currentProduct == nil) {
currentProduct = [[Product alloc] initWithEntity:self.productEntityDescription insertIntoManagedObjectContext:self.insertionContext];
}
return currentProduct;
}
// Forward errors to delegate
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self performSelectorOnMainThread:#selector(forwardError:) withObject:error waitUntilDone:NO];
done = YES; // End run loop
}
// Called when a chunk of data has been downloaded
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Process downloaded chunk of data
xmlParseChunk(context, (const char *)[data bytes], [data length], 0);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Signal the context that parsing is complete by passing "1" as last parameter
xmlParseChunk(context, NULL, 0, 1);
context = NULL;
done = YES; // End the loop
}
static const NSUInteger kImportBatchSize = 20;
- (void)finishedCurrentProduct {
parsingAProduct = NO;
self.currentProduct = nil;
countForCurrentBatch++;
if (countForCurrentBatch == kImportBatchSize) {
NSError *saveError = nil;
NSAssert1([insertionContext save:&saveError], #"Unhandled error saving managed object context in import thread: %#", [saveError localizedDescription]);
countForCurrentBatch = 0;
}
}
// Character data appended to a buffer until current element ends.
- (void)appendCharacters:(const char *)charactersFound length:(NSInteger)length {
[characterBuffer appendBytes:charactersFound length:length];
}
- (NSString *)currentString {
// Create a string with character data using UTF-8 encoding
NSString *currentString = [[NSString alloc] initWithData:characterBuffer encoding:NSUTF8StringEncoding];
[characterBuffer setLength:0];
return currentString;
}
#end
// XML element names, string lengths for parsing
static const char *kName_App = "App"; // Product container tag
static const NSUInteger kLength_App = 4;
static const char *kName_Sku = "prod_sku";
static const NSUInteger kLength_Sku = 9;
static const char *kName_Name = "prod_name";
static const NSUInteger kLength_Name = 10;
static const char *kName_Description = "prod_description";
static const NSUInteger kLength_Description = 17;
static const char *kName_Category = "prod_category";
static const NSUInteger kLength_Category = 14;
static const char *kName_Upc = "prod_upc";
static const NSUInteger kLength_Upc = 9;
static const char *kName_CountryCode = "prod_code_destination";
static const NSUInteger kLength_CountryCode = 22;
static const char *kName_Webpage = "prod_html_link";
static const NSUInteger kLength_Webpage = 15;
static const char *kName_Manual = "prod_manual";
static const NSUInteger kLength_Manual = 12;
static const char *kName_QuickStart = "prod_quick_start";
static const NSUInteger kLength_QuickStart = 17;
static const char *kName_Thumbnail = "prod_thumbnail";
static const NSUInteger kLength_Thumbnail = 15;
static const char *kName_MainImage = "prod_image_main";
static const NSUInteger kLength_MainImage = 16;
static const char *kName_SecondaryImage = "prod_image_secondary";
static const NSUInteger kLength_SecondaryImage = 21;
// Invoked when importer finds beginning of a node
static void startElementSAX(void *parsingContext, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI,
int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes) {
companyXMLImporter *importer = (__bridge companyXMLImporter *)parsingContext;
if (!strncmp((const char *)localname, kName_App, kLength_App)) {
importer.parsingAProduct = YES;
} else if (importer.parsingAProduct && ((!strncmp((const char *)localname, kName_Sku, kLength_Sku) || !strncmp((const char *)localname, kName_Name, kLength_Name) || !strncmp((const char *)localname, kName_Description, kLength_Description) || !strncmp((const char *)localname, kName_Category, kLength_Category) || !strncmp((const char *)localname, kName_Upc, kLength_Upc) || !strncmp((const char *)localname, kName_CountryCode, kLength_CountryCode) || !strncmp((const char *)localname, kName_Webpage, kLength_Webpage) || !strncmp((const char *)localname, kName_Manual, kLength_Manual) || !strncmp((const char *)localname, kName_QuickStart, kLength_QuickStart) || !strncmp((const char *)localname, kName_Thumbnail, kLength_Thumbnail) || !strncmp((const char *)localname, kName_MainImage, kLength_MainImage) || !strncmp((const char *)localname, kName_SecondaryImage, kLength_SecondaryImage)))
) {
importer.storingCharacters = YES;
}
}
// Invoked when parse reaches end of a node
static void endElementSAX(void *parsingContext, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI) {
companyXMLImporter *importer = (__bridge companyXMLImporter *)parsingContext;
if (importer.parsingAProduct == NO) return;
if (!strncmp((const char *)localname, kName_App, kLength_App)) {
[importer finishedCurrentProduct];
} else if (!strncmp((const char *)localname, kName_Name, kLength_Name)) {
importer.currentProduct.name = importer.currentString;
} else if (!strncmp((const char *)localname, kName_Category, kLength_Category)) {
double before = [NSDate timeIntervalSinceReferenceDate];
Category *category = [importer.theCache categoryWithName:importer.currentString];
double delta = [NSDate timeIntervalSinceReferenceDate] - before;
lookuptime += delta;
importer.currentProduct.category = category;
} else if (!strncmp((const char *)localname, kName_Sku, kLength_Sku)) {
importer.currentProduct.sku = importer.currentString;
} else if (!strncmp((const char *)localname, kName_Description, kLength_Description)) {
importer.currentProduct.prodDescription = importer.currentString;
} else if (!strncmp((const char *)localname, kName_Upc, kLength_Upc)) {
importer.currentProduct.upc = importer.currentString;
} else if (!strncmp((const char *)localname, kName_CountryCode, kLength_CountryCode)) {
importer.currentProduct.countryCode = importer.currentString;
} else if (!strncmp((const char *)localname, kName_Webpage, kLength_Webpage)) {
importer.currentProduct.webpage = importer.currentString;
} else if (!strncmp((const char *)localname, kName_Manual, kLength_Manual)) {
importer.currentProduct.manual = importer.currentString;
} else if (!strncmp((const char *)localname, kName_QuickStart, kLength_QuickStart)) {
importer.currentProduct.quickStart = importer.currentString;
} else if (!strncmp((const char *)localname, kName_Thumbnail, kLength_Thumbnail)) {
importer.currentProduct.thumbURLString = importer.currentString;
} else if (!strncmp((const char *)localname, kName_MainImage, kLength_MainImage)) {
importer.currentProduct.mainImgURLString = importer.currentString;
} else if (!strncmp((const char *)localname, kName_SecondaryImage, kLength_SecondaryImage)) {
importer.currentProduct.secondaryImgURLString = importer.currentString;
}
importer.storingCharacters = NO;
}
// Invoked when parser encounters character data inside a node
static void charactersFoundSAX(void *parsingContext, const xmlChar *characterArray, int numberOfCharacters) {
companyXMLImporter *importer = (__bridge companyXMLImporter *)parsingContext;
// storingCharacters set when nodes of interest begin/end – determines whether character data handled/ignored
if (importer.storingCharacters == NO) return;
[importer appendCharacters:(const char *)characterArray length:numberOfCharacters];
}
// Error handling
static void errorEncounteredSAX(void *parsingContext, const char *errorMessage, ...) {
// Handle errors as appropriate
NSCAssert(NO, #"Unhandled error encountered during SAX parse.");
}
static xmlSAXHandler simpleSAXHandlerStruct = {
NULL, /* internalSubset */
NULL, /* isStandalone */
NULL, /* hasInternalSubset */
NULL, /* hasExternalSubset */
NULL, /* resolveEntity */
NULL, /* getEntity */
NULL, /* entityDecl */
NULL, /* notationDecl */
NULL, /* attributeDecl */
NULL, /* elementDecl */
NULL, /* unparsedEntityDecl */
NULL, /* setDocumentLocator */
NULL, /* startDocument */
NULL, /* endDocument */
NULL, /* startElement*/
NULL, /* endElement */
NULL, /* reference */
charactersFoundSAX, /* characters */
NULL, /* ignorableWhitespace */
NULL, /* processingInstruction */
NULL, /* comment */
NULL, /* warning */
errorEncounteredSAX, /* error */
NULL,/* fatalError //: unused error() get all the errors */
NULL, /* getParameterEntity */
NULL, /* cdataBlock */
NULL, /* externalSubset */
XML_SAX2_MAGIC, //
NULL,
startElementSAX, /* startElementNs */
endElementSAX, /* endElementNs */
NULL, /* serror */
};
You should not need to call reloadData at all to get the data to display in the table ... and you're calling it twice, in viewDidLoad and in fetch. I would get rid of these.
It does sound like you have a timing problem. Can you explain more about how the data gets into the database? When you say,
In modifying the XML file that this database pulls data from ...
I take it that you mean that when your app starts up, it reads from an XML file which is packaged with your app, and writes this information into Core Data / Sqlite. If that is indeed what you do, then maybe the problem is that this process is trying to run at the same time as your CategoriesViewController is loading. Where is the code which reads the XML into Core Data / Sqlite? Where do you call it from? Is it a synchronous or an asynchronous call?
Related
I'm also beginner for iOS technology. And as per my title saying that might be this question will helpful for each new developer.
So welcome to all edit my answer and correct me OR put your own answer to improve our knowledge.
In the below Example I'm considering
1) One table name is “Student”
2) Below are fields name
- First Name
- Last Name
- Address
- Birth Date
Here we can apply manipulate operation such like “Add”, “Update”, “Delete” and “Fetch” record from the table.
UPDATE :
As per other user's answer we also can mange by CoreData too. But CoreData is faster and easier then SQLite ? If data is complex then how can we manage by CoreData?
First we need to create SQLite database and table. I’m thinking there are so many way to create database and table but most sufficient way that I’m using
1) Install Firefox and Install Add-ons
https://addons.mozilla.org/en-US/firefox/addon/sqlite-manager/
2) Create Database
- Go on Firefox -> tools -> SQLite Manager
- Top left corner choose 3rd -> New Database OR On the menu bar, choose “Database” -> New Database
- Give Database name “student” and save right place in your project.
3) Create Table
- Left side menu-> select “Tables(0)” -> Right click - Create Table OR On the menu bar, choose “Table” -> Create Table
- Give Table name “student_info” and save right place in your project.
Belo Are the code for execute manipulate operation.
#import <Foundation/Foundation.h>
#import "sqlite3.h"
#interface SQLDb : NSObject
{
sqlite3 *_database;
NSString *savedDate;
}
#property (readwrite) sqlite3* _database;
#property (nonatomic, strong) NSString *savedDate;
+(SQLDb *) initEngine;
+ (SQLDb*) database ;
+(void)releaseEngine;
- (void) executeQuery:(NSString *)query;
-(void) insertRecordInStuentTable:(NSMutableDictionary *) dicOfStudent;
-(NSMutableArray *) getRecordFrom_bannerTable;
-(void)updateNameOfStuden:(NSString *)studentName withRollNumber:(NSString *)strRollNumber;
-(void) deleteAllDataFrom_Student_Table;
And for .m file
#import "SQLDb.h"
#implementation SQLDb
////Getters / Setters
#synthesize _database, savedDate;
static SQLDb* _database = nil;
//start for initialization of database
#pragma mark - Initialization Methods -
+ (SQLDb*)database
{
if (_database == nil)
_database = [[SQLDb alloc] init];
return _database;
}
+(SQLDb *) initEngine
{
if ( !_database )
{
NSString *databaseName = #“student.sqlite";
[SQLDb createEditableCopyOfFileIfNeeded:databaseName];
sqlite3 *db = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:databaseName];
NSLog(#"DB path - %#", path);
const char* dbName = [path UTF8String];
if ( sqlite3_open(dbName,&db) != SQLITE_OK )
{
NSException* initException;
initException = [NSException exceptionWithName:#"SQL Exception" reason:#"Database Initialization Failed" userInfo:nil];
#throw initException;
}
_database = [[self allocWithZone: NULL] init] ;
_database._database = db;
}
return _database;
}
+ (void)createEditableCopyOfFileIfNeeded:(NSString *)fileName
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:fileName];
BOOL success = [fileManager fileExistsAtPath:writableDBPath];
if (success)
return;
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:fileName];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
NSLog(#"Database Path - %#", writableDBPath);
if (!success)
NSLog(#"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
-(void) executeQuery:(NSString *)query
{
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil) == SQLITE_OK)
{
char *selectQuery = sqlite3_mprintf([query UTF8String]);
sqlite3_free(selectQuery);
sqlite3_step(statement);
sqlite3_finalize(statement);
}
}
+(void) releaseEngine
{
sqlite3_close(_database._database);
_database._database = nil;
_database = nil;
}
//==================================
-(void) insertBannerInTable:(NSMutableDictionary *) dicOfStuent
{
int ret;
const char *sql = "INSERT INTO `student` (‘firstname’, ‘lastname’, ‘bdate’, ‘address’) VALUES (?, ?, ?, ?);";
sqlite3_stmt *insStmt = NULL;
if ( !insStmt )
if ( (ret = sqlite3_prepare_v2(_database, sql, -1, &insStmt, NULL)) != SQLITE_OK ) {
NSLog(#"Proble to insert record in student");
}
// bind values
sqlite3_bind_text(insStmt, 1, [[NSString stringWithFormat:#"%#", [dicOfStuent objectForKey:#"firstname"]] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(insStmt, 2, [[NSString stringWithFormat:#"%#", [dicOfStuent objectForKey:#"lastname"]] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(insStmt, 3, [[NSString stringWithFormat:#"%#", [dicOfStuent objectForKey:#"bdate"]] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(insStmt, 4, [[NSString stringWithFormat:#"%#", [dicOfStuent objectForKey:#“address”]] UTF8String], -1, SQLITE_TRANSIENT);
if ((ret = sqlite3_step(insStmt)) != SQLITE_DONE) {NSLog(#"error while inserting data in 'student' table");}
sqlite3_reset(insStmt);
}
-(NSMutableArray *) getRecordFrom_StudentTable
{
NSMutableArray *listofStudent = [[NSMutableArray alloc] init];
sqlite3_stmt *statement = NULL;
NSString *query = [NSString stringWithFormat:#"SELECT * FROM bannerTable"];
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
//('banner_id', 'banner_image', 'banner_type', 'banner_description', 'banner_link') VALUES (?, ?, ?, ?, ?)
char *mainIDChars = (char *) sqlite3_column_text(statement, 0);
char *bnrIdChars = (char *) sqlite3_column_text(statement, 1);
char *bnrImgChars = (char *) sqlite3_column_text(statement, 2);
char *bnrTypChars = (char *) sqlite3_column_text(statement, 3);
char *bnrDesChars = (char *) sqlite3_column_text(statement, 4);
char *bnrLinkChars = (char *) sqlite3_column_text(statement, 5);
NSString *mainID = #"", *advertisement_id = #"", *advertisement_image = #"", *advertisement_type = #"", *advertisement_description = #"", *advertisement_link = #"";
if(mainIDChars != NULL)
mainID = [[NSString alloc] initWithUTF8String:mainIDChars];
if(bnrIdChars != NULL)
advertisement_id = [[NSString alloc] initWithUTF8String:bnrIdChars];
if(bnrImgChars != NULL)
advertisement_image = [[NSString alloc] initWithUTF8String:bnrImgChars];
if(bnrTypChars != NULL)
advertisement_type = [[NSString alloc] initWithUTF8String:bnrTypChars];
if(bnrDesChars != NULL)
advertisement_description = [[NSString alloc] initWithUTF8String:bnrDesChars];
if(bnrLinkChars != NULL)
advertisement_link = [[NSString alloc] initWithUTF8String:bnrLinkChars];
NSMutableDictionary *dicOfStuent = [[ NSMutableDictionary alloc] init];
[dicOfStuent setObject:mainID forKey:#"main_id"];
[dicOfStuent setObject:advertisement_id forKey:#"advertisement_id"];
[dicOfStuent setObject:advertisement_image forKey:#"advertisement_image"];
[dicOfStuent setObject:advertisement_type forKey:#"is_image_url"];
[dicOfStuent setObject:advertisement_description forKey:#"advertisement_description"];
[dicOfStuent setObject:advertisement_link forKey:#"advertisement_link"];
[listofStudent addObject:dicOfStuent];
}
sqlite3_finalize(statement);
}
return listofStudent;
}
-(void)updateNameOfStuden:(NSString *)studentName withRollNumber:(NSString *)strRollNumber
{
int ret;
const char *sql = "update user_Group_ChatList set is_online = ? where Jabber_id = ?;";
sqlite3_stmt *updtStmt = NULL;
if ( !updtStmt )
if ( (ret = sqlite3_prepare_v2(_database, sql, -1, &updtStmt, NULL)) != SQLITE_OK ) {}
// bind values
sqlite3_bind_text(updtStmt, 1, [[NSString stringWithFormat:#"%#", strProductID] UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(updtStmt, 2, [strTotalProduct UTF8String], -1, SQLITE_TRANSIENT);
if ((ret = sqlite3_step(updtStmt)) != SQLITE_DONE) {NSLog(#"error while updating QTY from ProductsCart Table");}
sqlite3_reset(updtStmt);
}
-(void) deleteAllDataFrom_Student_Table
{
int ret;
const char *sql = "DELETE FROM student";
sqlite3_stmt *dltStmt = NULL;
if ( !dltStmt )
if ( (ret = sqlite3_prepare_v2(_database, sql, -1, &dltStmt, NULL)) != SQLITE_OK ) {}
if ((ret = sqlite3_step(dltStmt)) != SQLITE_DONE) {NSLog(#"Error : While Deleting Record From user_Group_ChatList Table");}
sqlite3_reset(dltStmt);
}
Above are .H and .M file that will help you to manage SQLite database.
If you are a beginner to iOS technology and want to learn local storage management then i will suggest you to go with CoreData:
Manage Local storage using Core Data
Because using core data you can interact with local database in a form of object and class.
According to your Question most of them say
Coredta is better than SQLite
When you use SQLite using Adds-on tool we need to do the below things.I explain you clearly.
My DB Name is - LoginRegistration.sqlite
My DB Table Name is - TblReg
I have Login Screen.In that I have username and password field.Below that I have Login and Register Button.
When you click register button it goes to registration page view controller where we have to register first then we have to save the data on insert the data into our SQLite db.
For implementing SQLite,first we must add and import the sqlite3.h.
DatabaseOne.h
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#interface DatabaseOne : NSObject{
sqlite3 *SQLDB;
NSString *dbName;
}
+(DatabaseOne *)sharedDB;
-(id)init;
- (id)initWithName:(NSString *)dbname;
- (void)createDB:(NSString *)dbname;
- (NSString *)getDBPath;
- (void)copyDatabaseIfNeeded;
- (BOOL)executeQuery:(NSString *)query;
- (NSString*)checkForNull:(char*)colValue;
- (NSMutableArray *)executeSelectQuery:(NSString *)query;
#end
DatabaseOne.m
#import "DatabaseOne.h"
#implementation DatabaseOne
static DatabaseOne *shared = nil;
/***
Create a single GSSQL instance
***/
+(DatabaseOne *)sharedDB;
{
#synchronized([DatabaseOne class])
{
if (!shared) {
return [[self alloc] init];
}
return shared;
}
return nil;
}
-(id)init
{
shared = [super init];
return shared;
}
-(id)initWithName:(NSString *)dbname;
{
self = [super init];
if (self) {
dbName =[[NSString alloc] initWithString:dbname];
[self copyDatabaseIfNeeded];
}
return self;
}
/***
Create a DB on documents with the name you given dbname;
***/
- (void)createDB:(NSString *)dbname;
{
dbName = [[NSString alloc] initWithString:dbname];
[shared copyDatabaseIfNeeded];
}
/***
Get the DB Path of Database exists in documents folder
***/
- (NSString *) getDBPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:dbName];
}
/***
Creates and copies the DB from Resources to documents directory
***/
- (void)copyDatabaseIfNeeded {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [self getDBPath];
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:dbName];
BOOL isResourceAvail = [fileManager fileExistsAtPath:defaultDBPath];
if (isResourceAvail == NO) {
NSLog(#"DB %# is not exists in Resource to be copied",dbName);
}else
{
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(!success) {
NSLog(#"Copying the DB %#", defaultDBPath);
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to copy database: '%#'.", [error localizedDescription]);
}
}
}
#pragma mark - query execution
/***
Execute the query string(NSString *)
***/
-(BOOL)executeQuery:(NSString *)query;
{
BOOL done = NO;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(success) {
int sql_results = sqlite3_open([dbPath UTF8String], &SQLDB);
const char *sql = [query UTF8String];
if (sql_results == SQLITE_OK) {
if(sqlite3_exec(SQLDB, sql, nil, nil, nil) == SQLITE_OK) {
printf("Good SQL\n");
done = YES;
}
else {
NSLog(#"Bad SQL: %s -- %d", sql,sql_results);
//NSLog(#"Bad SQL:%d",sql_results);
}
}
else {
printf("DB Open FAILED\n");
NSLog(#"error code %i", sql_results);
}
sqlite3_close(SQLDB);
}
else {
printf("DB not exists in application folder\n");
}
return done;
}
/***
Executes select query and returns array of results
***/
-(NSMutableArray *)executeSelectQuery:(NSString *)query
{
NSMutableArray *results = [[NSMutableArray alloc] init];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(success) {
int sql_results = sqlite3_open([dbPath UTF8String], &SQLDB);
if (sql_results == SQLITE_OK) {
const char *sql = [query UTF8String];
sqlite3_stmt *selectStmt = nil;
if (sqlite3_prepare_v2(SQLDB, sql, -1, &selectStmt, NULL) == SQLITE_OK) {
while (sqlite3_step(selectStmt) == SQLITE_ROW) {
int columnCount = sqlite3_column_count(selectStmt);
NSMutableDictionary *row = [NSMutableDictionary dictionary];
for (int i = 0; i < columnCount; i++) {
NSString *column_name = [self checkForNull:(char *)sqlite3_column_name(selectStmt, i)];
NSString *column_value = [self checkForNull:(char *)sqlite3_column_text(selectStmt, i)];
[row setValue:column_value forKey:column_name];
}
[results addObject:row];
}
}
sqlite3_reset(selectStmt);
}
sqlite3_close(SQLDB);
}
else {
printf("DB not exists in application folder\n");
}
return results;
}
/***
Checks for a NULL value
***/
- (NSString*)checkForNull:(char*)colValue {
NSString *returnValue = #"something";
if(colValue) {
returnValue = [NSString stringWithUTF8String:colValue];
}
else {
returnValue = #"nil";
}
return(returnValue);
}
#end
Now the Modal data are
Register.h
#import <Foundation/Foundation.h>
#interface Register : NSObject
#property (nonatomic,retain) NSString *strFirstName;
#property (nonatomic,retain) NSString *strLastName;
#property (nonatomic,retain) NSString *strEmailId;
#property (nonatomic,retain) NSString *strPassword;
#property (nonatomic,retain) NSString *strMobileNo;
#property (nonatomic,retain) NSString *strMilliSeconds;
#property (nonatomic,retain) NSString *IsRegister;
-(id)init;
#end
Register.m
#import "Register.h"
#implementation Register
#synthesize strPassword = _strPassword;
#synthesize strMobileNo = _strMobileNo;
#synthesize strEmailId = _strEmailId;
#synthesize strFirstName = _strFirstName;
#synthesize strLastName = _strLastName;
#synthesize strMilliSeconds = _strMilliSeconds;
#synthesize IsRegister = _IsRegister;
-(id)init
{
self = [super init];
if (self != nil)
{
_strFirstName = [[NSString alloc]init];
_strEmailId = [[NSString alloc]init];
_strPassword = [[NSString alloc]init];
_strLastName = [[NSString alloc]init];
_strMobileNo = [[NSString alloc]init];
_strMilliSeconds = [[NSString alloc]init];
_IsRegister = [[NSString alloc]init];
}
return self;
}
#end
Here I set the intermediate for ViewController(RegisterPage)-DataBase
ViewController_DBConnection.h
#import <Foundation/Foundation.h>
#import "Register.h"
#import "DatabaseOne.h"
#interface ViewController_DBConnection : NSObject
+(void)registerDB:(Register *)registerDB;
+(NSMutableArray *)GetRegisterAccount:(NSString *) whereQuery;
+(NSMutableArray *)GetRegisterDetail;
#end
ViewController_DBConnection.m
#import "ViewController_DBConnection.h"
#implementation ViewController_DBConnection
+(void)registerDB:(Register *)registerDB
{
NSString *query = [[NSString alloc]initWithFormat:#"INSERT into TblReg(Firstname,Lastname,EmailId,Password,Mobileno,Milliseconds)values(\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\")",registerDB.strFirstName,registerDB.strLastName,registerDB.strEmailId,registerDB.strPassword,registerDB.strMobileNo,registerDB.strMilliSeconds];
BOOL Success = [[DatabaseOne sharedDB]executeQuery:query];
if(Success)
{
[[NSNotificationCenter defaultCenter]postNotificationName:#"Registration Success" object:nil];
}
}
+(void)update:(Register *)registerDB
{
NSString *query = [[NSString alloc]initWithFormat:#"update TblReg Set Firstname = '%#',Lastname = '%#',EmailId = '%#' ,Password = '%#',Mobileno = '%#' WHERE Milliseconds = '%#'",registerDB.strFirstName,registerDB.strLastName,registerDB.strEmailId,registerDB.strPassword,registerDB.strMobileNo,registerDB.strMilliSeconds];
BOOL Success = [[DatabaseOne sharedDB]executeQuery:query];
if(Success)
{
[[NSNotificationCenter defaultCenter]postNotificationName:#"Updation Success" object:nil];
}
}
+(NSMutableArray *)GetRegisterAccount:(NSString *) whereQuery
{
NSString *query=[[NSString alloc]initWithFormat:#"select * from TblReg WHERE %#;", whereQuery];
NSMutableArray *arrayData = [[DatabaseOne sharedDB]executeSelectQuery:query];
return arrayData;
}
+(NSMutableArray *)GetRegisterDetail
{
NSString *query=[[NSString alloc]initWithFormat:#"select * from Register"];
NSMutableArray *arrayData = [[DatabaseOne sharedDB]executeSelectQuery:query];
return arrayData;
}
#end
Now my Register View Controller
ViewController.h
#import <UIKit/UIKit.h>
#import "DatabaseOne.h"
#import "ViewController_DBConnection.h"
#import "Register.h"
#interface ViewController : UIViewController<UITextFieldDelegate,UITextViewDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate>{
Register *registerDB;
}
#property (strong, nonatomic) IBOutlet UITextField *firstNameTxtFld;
#property (strong, nonatomic) IBOutlet UITextField *lastNameTextField;
#property (strong, nonatomic) IBOutlet UIImageView *imageViewData;
#property (strong, nonatomic) IBOutlet UITextField *emaiIdTextField;
#property (strong, nonatomic) IBOutlet UITextField *passwordTextField;
#property (strong, nonatomic) IBOutlet UITextField *ConfirmPasswordtextField;
#property (strong, nonatomic) IBOutlet UITextField *mobilenoTextField;
- (IBAction)actionSave:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController (){
CGFloat animatedDistance;
NSMutableArray *arrayDBGetData;
}
#end
#implementation ViewController
#synthesize firstNameTxtFld,lastNameTextField,emaiIdTextField,passwordTextField,ConfirmPasswordtextField,mobilenoTextField;
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.2;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[DatabaseOne sharedDB] createDB:#"LoginRegistration.sqlite"];
arrayDBGetData = [[NSMutableArray alloc]init];
registerDB = [[Register alloc]init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//pragma mark - UITextField Dlelgate method
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if (![textField isEqual:firstNameTxtFld]) {
CGRect textViewRect = [self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat midline = textViewRect.origin.y + 0.5 * textViewRect.size.height;
CGFloat numerator = midline - viewRect.origin.y - MINIMUM_SCROLL_FRACTION * viewRect.size.height;
CGFloat denominator = (MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION) * viewRect.size.height;
CGFloat heightFraction = numerator / denominator;
if (heightFraction < 0.0)
{
heightFraction = 0.0;
}
else if (heightFraction > 1.0)
{
heightFraction = 1.0;
}
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
CGRect viewFrame = self.view.frame;
viewFrame.origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
CGRect viewFrame = self.view.frame;
viewFrame.origin.y += animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
- (IBAction)actionSave:(id)sender{
registerDB.strFirstName = firstNameTxtFld.text;
registerDB.strLastName = lastNameTextField.text;
registerDB.strEmailId = emaiIdTextField.text;
registerDB.strPassword = passwordTextField.text;
registerDB.strMobileNo = mobilenoTextField.text;
[self getMilliSeconds];
arrayDBGetData = [ViewController_DBConnection GetRegisterAccount:[NSString stringWithFormat:#"EmailId = \"%#\"",registerDB.strEmailId]];
if([firstNameTxtFld.text length]==0||[lastNameTextField.text length]==0 || [emaiIdTextField.text length]==0 || [ConfirmPasswordtextField.text length] ==0 || [mobilenoTextField.text length]==0){
[self showAlertController:#"Error!" passMessage:#"Please Enter All Fields"];
}
else if([self emailValidation:registerDB.strEmailId] == FALSE){
[self showAlertController:#"Error!" passMessage:#"Please Enter Valid Email Address"];
}
else if(![passwordTextField.text isEqualToString:ConfirmPasswordtextField.text]){
[self showAlertController:#"Error!" passMessage:#"Please Enter matching password"];
}
else if([self checkNumeric:registerDB.strMobileNo] == FALSE){
[self showAlertController:#"Error!" passMessage:#"Please Enter Valid Mobile No"];
}
else if([arrayDBGetData count]!=0){
[self showAlertController:#"Warning !" passMessage:#"Already user have this Email Address.Try New?"];
}
else{
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"Registration Success" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(registrationSuccess:)
name:#"Registration Success"
object:nil];
[ViewController_DBConnection registerDB:registerDB];
}
}
//For Checking mail with - example#gmail.com
-(BOOL)checkValidEmail:(NSString *)checkString{
BOOL stricterFilter = NO;
NSString *stricterFilterString = #"^[A-Z0-9a-z\\._%+-]+#([A-Za-z0-9-]+\\.)+[A-Za-z]{2,4}$";
NSString *laxString = #"^.+#([A-Za-z0-9-]+\\.)+[A-Za-z]{2}[A-Za-z]*$";
NSString *emailRegex = stricterFilter ? stricterFilterString : laxString;
NSPredicate *emailTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", emailRegex];
return [emailTest evaluateWithObject:checkString];
}
//For Checking mail with - ex#m.in
- (BOOL)emailValidation:(NSString *)email {
NSString *emailRegEx =
#"(?:[a-z0-9!#$%\\&'*+/=?\\^_`{|}~-]+(?:\\.[a-z0-9!#$%\\&'*+/=?\\^_`{|}"
#"~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\"
#"x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")#(?:(?:[a-z0-9](?:[a-"
#"z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5"
#"]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-"
#"9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21"
#"-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])";
NSPredicate *regExPredicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", emailRegEx];
BOOL myStringMatchesRegEx = [regExPredicate evaluateWithObject:[email lowercaseString]];
return myStringMatchesRegEx;
}
//For checking Mobile No
- (BOOL)checkNumeric:(NSString *)textvalue {
NSCharacterSet *nonNumberSet = [[NSCharacterSet characterSetWithRange:NSMakeRange('0',10)] invertedSet];
NSString *trimmed = [textvalue stringByTrimmingCharactersInSet:[NSCharacterSet symbolCharacterSet]];
BOOL isNumeric = trimmed.length > 0 && [trimmed rangeOfCharacterFromSet:nonNumberSet].location == NSNotFound;
return isNumeric;
}
-(void)getMilliSeconds{
NSDate *now = [[NSDate alloc] init];
NSDateFormatter *datetimeFormatter =[[NSDateFormatter alloc]init];
[datetimeFormatter setDateFormat:#"ddMMyyyyHHmmssSS"];
registerDB.strMilliSeconds=[datetimeFormatter stringFromDate:now];
}
-(void)showAlertController:(NSString *)title passMessage:(NSString *)message{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
}
-(void)registrationSuccess:(NSNotification *)notification
{
if([[notification name] isEqualToString:#"Registration Success"]){
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"Success !" message:#"Registered Successfully" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action){
[self.navigationController popToRootViewControllerAnimated:YES];
}];
[alert addAction:okAction];
[self presentViewController:alert animated:YES completion:nil];
}
}
#end
Now Finally I check the login screen once I registered successfully.
RootViewController.h
#import <UIKit/UIKit.h>
#import "ViewController_DBConnection.h"
#interface RootViewController : UIViewController<UITextFieldDelegate>
#property (strong, nonatomic) IBOutlet UITextField *usernameTextField;
#property (strong, nonatomic) IBOutlet UITextField *passwordTextField;
- (IBAction)actionLogin:(id)sender;
#end
RootViewController.m
#import "RootViewController.h"
#interface RootViewController ()
{
NSMutableArray *arrayGetDBData;
CGFloat animatedDistance;
}
#end
#implementation RootViewController
#synthesize usernameTextField,passwordTextField;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[[DatabaseOne sharedDB] createDB:#"LoginRegistration.sqlite"];
arrayGetDBData = [[NSMutableArray alloc]init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)actionLogin:(id)sender {
//#"Error !" message:#"Username or Password is not correct"
if([usernameTextField.text length]==0||[passwordTextField.text length]==0){
[self showAlertController:#"Error!" passMessage:#"Please Enter the missing Fields"];
}
else{
arrayGetDBData = [ViewController_DBConnection GetRegisterAccount:[NSString stringWithFormat:#"Emailid = \"%#\"",usernameTextField.text]];
if(arrayGetDBData.count==0){
[self showAlertController:#"Error!" passMessage:#"Username is not correct"];
}
else if(![passwordTextField.text isEqualToString:[[arrayGetDBData objectAtIndex:0]valueForKey:#"Password"]])
{
[self showAlertController:#"Error!" passMessage:#"Password is not correct"];
}else{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"Success" message:#"Successfully Logged" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action){
}];
[alert addAction:okAction];
[self presentViewController:alert animated:YES completion:nil];
}
}
}
-(void)showAlertController:(NSString *)title passMessage:(NSString *)message{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
}
#pragma mark - UITextField Delegate Methods
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.3;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat midline = textFieldRect.origin.y + 0.5 * textFieldRect.size.height;
CGFloat numerator = midline - viewRect.origin.y - MINIMUM_SCROLL_FRACTION * viewRect.size.height;
CGFloat denominator = (MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION) * viewRect.size.height;
CGFloat heightFraction = numerator / denominator;
if (heightFraction < 0.0)
heightFraction = 0.0;
else if (heightFraction > 1.0)
heightFraction = 1.0;
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
CGRect viewFrame = self.view.frame;
viewFrame.origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
CGRect viewFrame = self.view.frame;
viewFrame.origin.y += animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
#end
Above I checked everything very clearly.It works perfectly.
Here is my answer for updating and deleting the row from the table view
**DatabaseOne.h**
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#interface DatabaseOne : NSObject{
sqlite3 *SQLDB;
NSString *dbName;
}
+(DatabaseOne *)sharedDB;
-(id)init;
- (id)initWithName:(NSString *)dbname;
- (void)createDB:(NSString *)dbname;
- (NSString *)getDBPath;
- (void)copyDatabaseIfNeeded;
- (BOOL)executeQuery:(NSString *)query;
- (NSString*)checkForNull:(char*)colValue;
- (NSMutableArray *)executeSelectQuery:(NSString *)query;
#end
DatabaseOne.m
#import "DatabaseOne.h"
#implementation DatabaseOne
static DatabaseOne *shared = nil;
/***
Create a single GSSQL instance
***/
+(DatabaseOne *)sharedDB;
{
#synchronized([DatabaseOne class])
{
if (!shared) {
return [[self alloc] init];
}
return shared;
}
return nil;
}
-(id)init
{
shared = [super init];
return shared;
}
-(id)initWithName:(NSString *)dbname;
{
self = [super init];
if (self) {
dbName =[[NSString alloc] initWithString:dbname];
[self copyDatabaseIfNeeded];
}
return self;
}
/***
Create a DB on documents with the name you given dbname;
***/
- (void)createDB:(NSString *)dbname;
{
dbName = [[NSString alloc] initWithString:dbname];
[shared copyDatabaseIfNeeded];
}
/***
Get the DB Path of Database exists in documents folder
***/
- (NSString *) getDBPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:dbName];
}
/***
Creates and copies the DB from Resources to documents directory
***/
- (void)copyDatabaseIfNeeded {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dbPath = [self getDBPath];
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:dbName];
BOOL isResourceAvail = [fileManager fileExistsAtPath:defaultDBPath];
if (isResourceAvail == NO) {
NSLog(#"DB %# is not exists in Resource to be copied",dbName);
}else
{
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(!success) {
NSLog(#"Copying the DB %#", defaultDBPath);
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, #"Failed to copy database: '%#'.", [error localizedDescription]);
}
}
}
#pragma mark - query execution
/***
Execute the query string(NSString *)
***/
-(BOOL)executeQuery:(NSString *)query;
{
BOOL done = NO;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(success) {
int sql_results = sqlite3_open([dbPath UTF8String], &SQLDB);
const char *sql = [query UTF8String];
if (sql_results == SQLITE_OK) {
if(sqlite3_exec(SQLDB, sql, nil, nil, nil) == SQLITE_OK) {
printf("Good SQL\n");
done = YES;
}
else {
NSLog(#"Bad SQL: %s -- %d", sql,sql_results);
//NSLog(#"Bad SQL:%d",sql_results);
}
}
else {
printf("DB Open FAILED\n");
NSLog(#"error code %i", sql_results);
}
sqlite3_close(SQLDB);
}
else {
printf("DB not exists in application folder\n");
}
return done;
}
/***
Executes select query and returns array of results
***/
-(NSMutableArray *)executeSelectQuery:(NSString *)query
{
NSMutableArray *results = [[NSMutableArray alloc] init];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *dbPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(success) {
int sql_results = sqlite3_open([dbPath UTF8String], &SQLDB);
if (sql_results == SQLITE_OK) {
const char *sql = [query UTF8String];
sqlite3_stmt *selectStmt = nil;
if (sqlite3_prepare_v2(SQLDB, sql, -1, &selectStmt, NULL) == SQLITE_OK) {
while (sqlite3_step(selectStmt) == SQLITE_ROW) {
int columnCount = sqlite3_column_count(selectStmt);
NSMutableDictionary *row = [NSMutableDictionary dictionary];
for (int i = 0; i < columnCount; i++) {
NSString *column_name = [self checkForNull:(char *)sqlite3_column_name(selectStmt, i)];
NSString *column_value = [self checkForNull:(char *)sqlite3_column_text(selectStmt, i)];
[row setValue:column_value forKey:column_name];
}
[results addObject:row];
}
}
sqlite3_reset(selectStmt);
}
sqlite3_close(SQLDB);
}
else {
printf("DB not exists in application folder\n");
}
return results;
}
/***
Checks for a NULL value
***/
- (NSString*)checkForNull:(char*)colValue {
NSString *returnValue = #"something";
if(colValue) {
returnValue = [NSString stringWithUTF8String:colValue];
}
else {
returnValue = #"nil";
}
return(returnValue);
}
#end
Now the Modal data are
Register.h
#import <Foundation/Foundation.h>
#interface Register : NSObject
#property (nonatomic,retain) NSString *strFirstName;
#property (nonatomic,retain) NSString *strLastName;
#property (nonatomic,retain) NSString *strEmailId;
#property (nonatomic,retain) NSString *strPassword;
#property (nonatomic,retain) NSString *strMobileNo;
#property (nonatomic,retain) NSString *strMilliSeconds;
#property (nonatomic,retain) NSString *IsRegister;
-(id)init;
#end
Register.m
#import "Register.h"
#implementation Register
#synthesize strPassword = _strPassword;
#synthesize strMobileNo = _strMobileNo;
#synthesize strEmailId = _strEmailId;
#synthesize strFirstName = _strFirstName;
#synthesize strLastName = _strLastName;
#synthesize strMilliSeconds = _strMilliSeconds;
#synthesize IsRegister = _IsRegister;
-(id)init
{
self = [super init];
if (self != nil)
{
_strFirstName = [[NSString alloc]init];
_strEmailId = [[NSString alloc]init];
_strPassword = [[NSString alloc]init];
_strLastName = [[NSString alloc]init];
_strMobileNo = [[NSString alloc]init];
_strMilliSeconds = [[NSString alloc]init];
_IsRegister = [[NSString alloc]init];
}
return self;
}
#end
Here I set the intermediate for ViewController(RegisterPage)-DataBase
ViewController_DBConnection.h
#import <Foundation/Foundation.h>
#import "Register.h"
#import "DatabaseOne.h"
#interface ViewController_DBConnection : NSObject
+(void)registerDB:(Register *)registerDB;
+(void)update:(Register *)registerDB;
+(void)delete:(Register *)registerDB;
+(NSMutableArray *)GetRegisterAccount:(NSString *) whereQuery;
+(NSMutableArray *)GetRegisterDetail;
#end
ViewController_DBConnection.m
#import "ViewController_DBConnection.h"
#implementation ViewController_DBConnection
+(void)registerDB:(Register *)registerDB
{
NSString *query = [[NSString alloc]initWithFormat:#"INSERT into TblReg(Firstname,Lastname,EmailId,Password,Mobileno,Milliseconds)values(\"%#\",\"%#\",\"%#\",\"%#\",\"%#\",\"%#\")",registerDB.strFirstName,registerDB.strLastName,registerDB.strEmailId,registerDB.strPassword,registerDB.strMobileNo,registerDB.strMilliSeconds];
BOOL Success = [[DatabaseOne sharedDB]executeQuery:query];
if(Success)
{
[[NSNotificationCenter defaultCenter]postNotificationName:#"Registration Success" object:nil];
}
}
+(void)update:(Register *)registerDB
{
NSString *query = [[NSString alloc]initWithFormat:#"update TblReg Set Firstname = '%#',Lastname = '%#',EmailId = '%#' ,Password = '%#',Mobileno = '%#' WHERE Milliseconds = '%#'",registerDB.strFirstName,registerDB.strLastName,registerDB.strEmailId,registerDB.strPassword,registerDB.strMobileNo,registerDB.strMilliSeconds];
BOOL Success = [[DatabaseOne sharedDB]executeQuery:query];
if(Success)
{
[[NSNotificationCenter defaultCenter]postNotificationName:#"Updation Success" object:nil];
}
}
+(void)delete:(Register *)registerDB
{
NSString *query = [[NSString alloc]initWithFormat:#"DELETE FROM TblReg where Milliseconds = '%#'",registerDB.strMilliSeconds];
BOOL Success = [[DatabaseOne sharedDB]executeQuery:query];
if(Success)
{
[[NSNotificationCenter defaultCenter]postNotificationName:#"Deletion Success" object:nil];
}
}
+(NSMutableArray *)GetRegisterAccount:(NSString *) whereQuery
{
NSString *query=[[NSString alloc]initWithFormat:#"select * from TblReg WHERE %#;", whereQuery];
NSMutableArray *arrayData = [[DatabaseOne sharedDB]executeSelectQuery:query];
return arrayData;
}
+(NSMutableArray *)GetRegisterDetail
{
NSString *query=[[NSString alloc]initWithFormat:#"select * from Register"];
NSMutableArray *arrayData = [[DatabaseOne sharedDB]executeSelectQuery:query];
return arrayData;
}
#end
EditViewController.h
#import <UIKit/UIKit.h>
#import "DatabaseOne.h"
#import "ViewController_DBConnection.h"
#import "Register.h"
#interface EditViewController : UIViewController{
Register *registerDB;
}
#property (strong, nonatomic) IBOutlet UITextField *firstnameTxtFld;
#property (strong, nonatomic) IBOutlet UITextField *lastnameTxtFld;
#property (strong, nonatomic) IBOutlet UITextField *emailidTxtFld;
#property (strong, nonatomic) IBOutlet UITextField *passwordTxtFld;
#property (strong, nonatomic) IBOutlet UITextField *mobilenoTxtFld;
#property (strong, nonatomic) NSString *strMilliSeconds;
#property (strong, nonatomic) NSString *strEmailId;
- (IBAction)actionEdit:(id)sender;
- (IBAction)actionBack:(id)sender;
- (IBAction)actionDeleteRow:(id)sender;
EditViewController.m
#import "EditViewController.h"
#interface EditViewController (){
NSMutableArray *arrayGetDBData;
CGFloat animatedDistance;
}
#end
#implementation EditViewController
#synthesize firstnameTxtFld,lastnameTxtFld,emailidTxtFld,passwordTxtFld,mobilenoTxtFld,strMilliSeconds,strEmailId;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[[DatabaseOne sharedDB] createDB:#"LoginRegistration.sqlite"];
arrayGetDBData = [[NSMutableArray alloc]init];
arrayGetDBData = [ViewController_DBConnection GetRegisterAccount:[NSString stringWithFormat:#"EmailId = \"%#\"",strEmailId]];
registerDB = [[Register alloc]init];
firstnameTxtFld.text = [[arrayGetDBData objectAtIndex:0]valueForKey:#"Firstname"];
lastnameTxtFld.text = [[arrayGetDBData objectAtIndex:0]valueForKey:#"Lastname"];
emailidTxtFld.text = [[arrayGetDBData objectAtIndex:0]valueForKey:#"EmailId"];
passwordTxtFld.text = [[arrayGetDBData objectAtIndex:0]valueForKey:#"Password"];
mobilenoTxtFld.text = [[arrayGetDBData objectAtIndex:0]valueForKey:#"Mobileno"];
registerDB.strMilliSeconds = [[arrayGetDBData objectAtIndex:0]valueForKey:#"Milliseconds"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UITextField Delegate Methods
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
static const CGFloat MINIMUM_SCROLL_FRACTION = 0.3;
static const CGFloat MAXIMUM_SCROLL_FRACTION = 0.8;
static const CGFloat PORTRAIT_KEYBOARD_HEIGHT = 216;
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
CGRect textFieldRect = [self.view.window convertRect:textField.bounds fromView:textField];
CGRect viewRect = [self.view.window convertRect:self.view.bounds fromView:self.view];
CGFloat midline = textFieldRect.origin.y + 0.5 * textFieldRect.size.height;
CGFloat numerator = midline - viewRect.origin.y - MINIMUM_SCROLL_FRACTION * viewRect.size.height;
CGFloat denominator = (MAXIMUM_SCROLL_FRACTION - MINIMUM_SCROLL_FRACTION) * viewRect.size.height;
CGFloat heightFraction = numerator / denominator;
if (heightFraction < 0.0)
heightFraction = 0.0;
else if (heightFraction > 1.0)
heightFraction = 1.0;
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
CGRect viewFrame = self.view.frame;
viewFrame.origin.y -= animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
CGRect viewFrame = self.view.frame;
viewFrame.origin.y += animatedDistance;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:KEYBOARD_ANIMATION_DURATION];
[self.view setFrame:viewFrame];
[UIView commitAnimations];
}
//For Checking mail with - ex#m.in
- (BOOL)emailValidation:(NSString *)email {
NSString *emailRegEx =
#"(?:[a-z0-9!#$%\\&'*+/=?\\^_`{|}~-]+(?:\\.[a-z0-9!#$%\\&'*+/=?\\^_`{|}"
#"~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\"
#"x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")#(?:(?:[a-z0-9](?:[a-"
#"z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5"
#"]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-"
#"9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21"
#"-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])";
NSPredicate *regExPredicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", emailRegEx];
BOOL myStringMatchesRegEx = [regExPredicate evaluateWithObject:[email lowercaseString]];
return myStringMatchesRegEx;
}
-(BOOL)isNumeric:(NSString*)inputString{
NSCharacterSet *charcter =[[NSCharacterSet characterSetWithCharactersInString:#"0123456789"] invertedSet];
NSString *filtered;
filtered = [[inputString componentsSeparatedByCharactersInSet:charcter] componentsJoinedByString:#""];
return [inputString isEqualToString:filtered];
}
- (BOOL)checkNumeric:(NSString *)textvalue {
NSCharacterSet *nonNumberSet = [[NSCharacterSet characterSetWithRange:NSMakeRange('0',10)] invertedSet];
NSString *trimmed = [textvalue stringByTrimmingCharactersInSet:[NSCharacterSet symbolCharacterSet]];
BOOL isNumeric = trimmed.length > 0 && [trimmed rangeOfCharacterFromSet:nonNumberSet].location == NSNotFound;
return isNumeric;
}
-(void)getMilliSeconds{
NSDate *now = [[NSDate alloc] init];
NSDateFormatter *datetimeFormatter =[[NSDateFormatter alloc]init];
[datetimeFormatter setDateFormat:#"ddMMyyyyHHmmssSS"];
registerDB.strMilliSeconds=[datetimeFormatter stringFromDate:now];
}
-(void)showAlertController:(NSString *)title passMessage:(NSString *)message{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:nil];
}
- (IBAction)actionEdit:(id)sender {
registerDB.strFirstName = firstnameTxtFld.text;
registerDB.strLastName = lastnameTxtFld.text;
registerDB.strEmailId = emailidTxtFld.text;
registerDB.strPassword = passwordTxtFld.text;
registerDB.strMobileNo = mobilenoTxtFld.text;
arrayGetDBData = [ViewController_DBConnection GetRegisterAccount:[NSString stringWithFormat:#"EmailId = \"%#\"",registerDB.strEmailId]];
if([firstnameTxtFld.text length]==0 || [lastnameTxtFld.text length]==0 || [emailidTxtFld.text length]==0 || [mobilenoTxtFld.text length]==0 || [passwordTxtFld.text length]==0){
[self showAlertController:#"Error!" passMessage:#"Please Enter All Fields"];
}
else if([self emailValidation:registerDB.strEmailId] == FALSE){
[self showAlertController:#"Error!" passMessage:#"Please Enter Valid Email Address"];
}
else if([self checkNumeric:registerDB.strMobileNo] == FALSE){
[self showAlertController:#"Error!" passMessage:#"Please Enter Valid Mobile No"];
}
else if([arrayGetDBData count]!=0){
[self showAlertController:#"Warning !" passMessage:#"Already user have this Email Address.Try New?"];
}
else{
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"Updation Success" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(updationSuccess:)
name:#"Updation Success"
object:nil];
[ViewController_DBConnection update:registerDB];
}
}
- (IBAction)actionDeleteRow:(id)sender
{
registerDB.strFirstName = firstnameTxtFld.text;
registerDB.strLastName = lastnameTxtFld.text;
registerDB.strEmailId = emailidTxtFld.text;
registerDB.strPassword = passwordTxtFld.text;
registerDB.strMobileNo = mobilenoTxtFld.text;
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"Deletion Success" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(deletionSuccess:)
name:#"Deletion Success"
object:nil];
[ViewController_DBConnection delete:registerDB];
}
- (IBAction)actionBack:(id)sender {
[self.navigationController popToRootViewControllerAnimated:YES];
}
-(void)updationSuccess:(NSNotification *)notification
{
if([[notification name] isEqualToString:#"Updation Success"])
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"Success !" message:#"Updated Successfully" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action){
[self.navigationController popToRootViewControllerAnimated:YES];
}];
[alert addAction:okAction];
[self presentViewController:alert animated:YES completion:nil];
}
}
-(void)deletionSuccess:(NSNotification *)notification
{
if([[notification name] isEqualToString:#"Deletion Success"])
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"Success !" message:#"Deleted Successfully" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action){
[self.navigationController popToRootViewControllerAnimated:YES];
}];
[alert addAction:okAction];
[self presentViewController:alert animated:YES completion:nil];
}
}
#end
I was trying to use NSHashTable to store some object pointers with weak references. During learning, I found that NSString(NSNumber) objects are not released after inserting it into [NSHashTable weakObjectsHashTable]. Any self defined class will work otherwise.
Any idea about why NSString(NSNumber) objects are not released?
#import <Foundation/Foundation.h>
#interface C : NSObject
#property(nonatomic) NSHashTable *hashTable;
#end
#implementation C
- (instancetype)init {
self = [super init];
if (self) {
_hashTable = [NSHashTable weakObjectsHashTable];
}
return self;
}
- (void)addObject:(NSObject *)obj {
[self.hashTable addObject:obj];
}
- (void)printAllObjects {
NSLog(#"Members: %#", [self.hashTable allObjects]);
[[self.hashTable allObjects] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(#"%p\n", obj);
}];
}
+ (void)hi:(C *)c {
#autoreleasepool {
NSString *s;
for(int i=0; i<10000; i++) {
s = [[NSString alloc] initWithFormat:#"%d", i];
[c addObject:s];
}
}
}
#end
void hi(C *c) {
NSString *i = #"hi";
NSLog(#"%p", i);
[c addObject:i];
}
int main(int argc, char *argv[]) {
C *c = [[C alloc] init];
#autoreleasepool {
[C hi:c];
}
[c printAllObjects];
}
Xcode Version is 8.1 (8B62) and output is:
2016-12-12 11:16:30.361 0x7fff9106c920
2016-12-12 11:16:30.362 Members: (
""
)
2016-12-12 11:16:30.362 0x7fff9106c920
Trying to import an XML file that has questions, answers, and categories for how-to questions. When I attempt to run this, there are supposed to be 3 categories (and they're visible in the XML file) of LB, OP, and DP. When I run the app, it seems to assign all how-tos to the LB category. What am I missing that's causing all to be assigned to the LB category? Thanks.
howToXMLImporter.h
#import <UIKit/UIKit.h>
#import <libxml/tree.h>
#class howToXMLImporter, HowTos, HowToCategory, HowToCategoryCache;
#protocol howToXMLImporterDelegate <NSObject>
#optional
- (void)importerDidSave:(NSNotification *)saveNotification;
- (void)importerDidFinishParsingData:(howToXMLImporter *)importer;
- (void)importer:(howToXMLImporter *)importer didFailWithError:(NSError *)error;
#end
#interface howToXMLImporter : NSOperation {
#private
id <howToXMLImporterDelegate> __unsafe_unretained delegate;
// Reference to the libxml parser context
xmlParserCtxtPtr context;
NSURLConnection *xmlConnection;
BOOL done;
BOOL parsingAHowTo;
BOOL storingCharacters;
NSMutableData *characterBuffer;
HowTos *currentHowTo; // Current how-to importer working with
// The number of parsed how-tos is tracked so that the autorelease pool for the parsing thread can be periodically emptied to keep the memory footprint under control.
NSUInteger countForCurrentBatch;
NSManagedObjectContext *insertionContext;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
NSEntityDescription *howToEntityDescription;
HowToCategoryCache *theCache;
NSURL *aogURL; // Source of the how-to XML file
}
#property (nonatomic, retain) NSURL *aogURL;
#property (nonatomic, assign) id <howToXMLImporterDelegate> delegate;
#property (nonatomic, retain) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (nonatomic, retain, readonly) NSManagedObjectContext *insertionContext;
#property (nonatomic, retain, readonly) NSEntityDescription *howToEntityDescription;
#property (nonatomic, retain, readonly) HowToCategoryCache *theCache;
- (void)main;
#end
howToXMLImporter.m
#import "howToXMLImporter.h"
#import "HowTos.h"
#import "HowToCategory.h"
#import "HowToCategoryCache.h"
#import <libxml/tree.h>
// Function prototypes for SAX callbacks.
static void startElementSAX(void *context, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes);
static void endElementSAX(void *context, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI);
static void charactersFoundSAX(void *context, const xmlChar *characters, int length);
static void errorEncounteredSAX(void *context, const char *errorMessage, ...);
// Forward reference. The structure is defined in full at the end of the file.
static xmlSAXHandler simpleSAXHandlerStruct;
// Class extension for private properties and methods.
#interface howToXMLImporter ()
#property BOOL storingCharacters;
#property (nonatomic, retain) NSMutableData *characterBuffer;
#property BOOL done;
#property BOOL parsingAHowTo;
#property NSUInteger countForCurrentBatch;
#property (nonatomic, retain) HowTos *currentHowTo;
#property (nonatomic, retain) NSURLConnection *xmlConnection;
#property (nonatomic, retain) NSDateFormatter *dateFormatter;
#end
static double lookuptime = 0;
#implementation howToXMLImporter
// Pull in these variables
#synthesize aogURL, delegate, persistentStoreCoordinator;
#synthesize xmlConnection, done, parsingAHowTo, storingCharacters, currentHowTo, countForCurrentBatch, characterBuffer;
- (void)main {
if (delegate && [delegate respondsToSelector:#selector(importerDidSave:)]) {
[[NSNotificationCenter defaultCenter] addObserver:delegate selector:#selector(importerDidSave:) name:NSManagedObjectContextDidSaveNotification object:self.insertionContext];
}
done = NO;
self.characterBuffer = [NSMutableData data];
NSURLRequest *theRequest = [NSURLRequest requestWithURL:aogURL];
// create the connection with the request and start loading the data
xmlConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
// This creates a context for "push" parsing in which chunks of data that are not "well balanced" can be passed to the context for streaming parsing.
context = xmlCreatePushParserCtxt(&simpleSAXHandlerStruct, (__bridge void *)(self), NULL, 0, NULL);
if (xmlConnection != nil) {
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);
}
// Release resources used only in this thread.
xmlFreeParserCtxt(context);
self.characterBuffer = nil;
self.dateFormatter = nil;
self.xmlConnection = nil;
self.currentHowTo = nil;
theCache = nil;
NSError *saveError = nil;
NSAssert1([insertionContext save:&saveError], #"Unhandled error saving managed object context in import thread: %#", [saveError localizedDescription]);
if (delegate && [delegate respondsToSelector:#selector(importerDidSave:)]) {
[[NSNotificationCenter defaultCenter] removeObserver:delegate name:NSManagedObjectContextDidSaveNotification object:self.insertionContext];
}
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(importerDidFinishParsingData:)]) {
[self.delegate importerDidFinishParsingData:self];
}
}
- (NSManagedObjectContext *)insertionContext {
if (insertionContext == nil) {
insertionContext = [[NSManagedObjectContext alloc] init];
[insertionContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
}
return insertionContext;
}
- (void)forwardError:(NSError *)error {
if (self.delegate != nil && [self.delegate respondsToSelector:#selector(importer:didFailWithError:)]) {
[self.delegate importer:self didFailWithError:error];
}
}
- (NSEntityDescription *)howToEntityDescription {
if (howToEntityDescription == nil) {
howToEntityDescription = [NSEntityDescription entityForName:#"HowTo" inManagedObjectContext:self.insertionContext];
}
return howToEntityDescription;
}
- (HowToCategoryCache *)theCache {
if (theCache == nil) {
theCache = [[HowToCategoryCache alloc] init];
theCache.managedObjectContext = self.insertionContext;
}
return theCache;
}
- (HowTos *)currentHowTo {
if (currentHowTo == nil) {
currentHowTo = [[HowTos alloc] initWithEntity:self.howToEntityDescription insertIntoManagedObjectContext:self.insertionContext];
}
return currentHowTo;
}
// Forward errors to the delegate.
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self performSelectorOnMainThread:#selector(forwardError:) withObject:error waitUntilDone:NO];
done = YES; // Ends the run loop.
}
// Called when a chunk of data has been downloaded.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Process downloaded chunk of data.
xmlParseChunk(context, (const char *)[data bytes], [data length], 0);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Signal the context that parsing is complete by passing "1" as the last parameter.
xmlParseChunk(context, NULL, 0, 1);
context = NULL;
done = YES; // Ends the run loop.
}
static const NSUInteger kImportBatchSize = 20;
- (void)finishedCurrentHowTo {
parsingAHowTo = NO;
self.currentHowTo = nil;
countForCurrentBatch++;
if (countForCurrentBatch == kImportBatchSize) {
NSError *saveError = nil;
NSAssert1([insertionContext save:&saveError], #"Unhandled error saving managed object context in how-to import thread: %#", [saveError localizedDescription]);
countForCurrentBatch = 0;
}
}
// Character data is appended to a buffer until the current element ends.
- (void)appendCharacters:(const char *)charactersFound length:(NSInteger)length {
[characterBuffer appendBytes:charactersFound length:length];
}
- (NSString *)currentString {
// Create a string with the character data using UTF-8 encoding
NSString *currentString = [[NSString alloc] initWithData:characterBuffer encoding:NSUTF8StringEncoding];
[characterBuffer setLength:0];
return currentString;
}
#end
// XML element names and their string lengths for parsing comparison; include null terminator
static const char *kName_HowTos = "How_Tos"; // Container tag for product
static const NSUInteger kLength_HowTos = 8;
static const char *kName_Question = "how-to_question"; // Didn't include how-to_id for now
static const NSUInteger kLength_Question = 16;
static const char *kName_Answer = "how-to_answer";
static const NSUInteger kLength_Answer = 14;
static const char *kName_Category = "how-to_category";
static const NSUInteger kLength_Category = 16;
static void startElementSAX(void *parsingContext, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI,
int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes) {
howToXMLImporter *importer = (__bridge howToXMLImporter *)parsingContext;
// The second parameter to strncmp is the name of the element, which we know from the XML schema of the feed. The third parameter to strncmp is the number of characters in the element name, plus 1 for the null terminator.
if (!strncmp((const char *)localname, kName_HowTos, kLength_HowTos)) {
importer.parsingAHowTo = YES;
// May want to set default variable values here
} else if (importer.parsingAHowTo &&
(
(!strncmp((const char *)localname, kName_Question, kLength_Question) ||
!strncmp((const char *)localname, kName_Answer, kLength_Answer) ||
!strncmp((const char *)localname, kName_Category, kLength_Category)
)
)
) {
importer.storingCharacters = YES;
}
}
// This callback is invoked when the parser reaches the end of a node
static void endElementSAX(void *parsingContext, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI) {
howToXMLImporter *importer = (__bridge howToXMLImporter *)parsingContext;
if (importer.parsingAHowTo == NO) return;
if (!strncmp((const char *)localname, kName_HowTos, kLength_HowTos)) {
[importer finishedCurrentHowTo];
} else if (!strncmp((const char *)localname, kName_Question, kLength_Question)) {
importer.currentHowTo.question = importer.currentString;
NSLog(#"Question: %#",importer.currentHowTo.question);
} else if (!strncmp((const char *)localname, kName_Answer, kLength_Answer)) {
importer.currentHowTo.answer = importer.currentString;
NSLog(#"Answer: %#",importer.currentHowTo.answer);
} else if (!strncmp((const char *)localname, kName_Category, kLength_Category)) {
double before = [NSDate timeIntervalSinceReferenceDate];
HowToCategory *category = [importer.theCache howToCategoryWithName:importer.currentString];
double delta = [NSDate timeIntervalSinceReferenceDate] - before;
lookuptime += delta;
importer.currentHowTo.category = category;
NSLog(#"Category: %#",importer.currentHowTo.category.name);
}
importer.storingCharacters = NO;
}
// This callback is invoked when the parser encounters character data inside a node. Importer class determines how to use the character data.
static void charactersFoundSAX(void *parsingContext, const xmlChar *characterArray, int numberOfCharacters) {
howToXMLImporter *importer = (__bridge howToXMLImporter *)parsingContext;
// A state variable, "storingCharacters", is set when nodes of interest begin and end. Determines whether character data is handled or ignored.
if (importer.storingCharacters == NO) return;
[importer appendCharacters:(const char *)characterArray length:numberOfCharacters];
}
static void errorEncounteredSAX(void *parsingContext, const char *errorMessage, ...) {
// Handle errors as appropriate
NSCAssert(NO, #"Unhandled error encountered during SAX parse.");
}
HowToCategoryCache.h
#import <Foundation/Foundation.h>
#class HowToCategory;
#interface HowToCategoryCache : NSObject {
NSManagedObjectContext *managedObjectContext;
NSUInteger cacheSize; // Number of objects that can be cached
NSMutableDictionary *cache; // A dictionary holds the actual cached items
NSEntityDescription *howToCategoryEntityDescription;
NSPredicate *howToCategoryNamePredicateTemplate;
NSUInteger accessCounter; // Counter used to determine the least recently touched item.
// Some basic metrics are tracked to help determine the optimal cache size for the problem.
CGFloat totalCacheHitCost;
CGFloat totalCacheMissCost;
NSUInteger cacheHitCount;
NSUInteger cacheMissCount;
}
#property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
#property NSUInteger cacheSize;
#property (nonatomic, strong) NSMutableDictionary *cache;
#property (nonatomic, strong, readonly) NSEntityDescription *howToCategoryEntityDescription;
#property (nonatomic, strong, readonly) NSPredicate *howToCategoryNamePredicateTemplate;
- (HowToCategory *)howToCategoryWithName:(NSString *)name;
#end
HowToCategoryCache.m
#import "HowToCategoryCache.h"
#import "HowToCategory.h"
// CacheNode is a simple object to help with tracking cached items
#interface HowToCacheNode : NSObject {
NSManagedObjectID *objectID;
NSUInteger accessCounter;
}
#property (nonatomic, strong) NSManagedObjectID *objectID;
#property NSUInteger accessCounter;
#end
#implementation HowToCacheNode
#synthesize objectID, accessCounter;
#end
#implementation HowToCategoryCache
#synthesize managedObjectContext, cacheSize, cache;
- (id)init {
self = [super init];
if (self != nil) {
cacheSize = 15;
accessCounter = 0;
cache = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
if (cacheHitCount > 0) NSLog(#"average cache hit cost: %f", totalCacheHitCost/cacheHitCount);
if (cacheMissCount > 0) NSLog(#"average cache miss cost: %f", totalCacheMissCost/cacheMissCount);
howToCategoryEntityDescription = nil;
howToCategoryNamePredicateTemplate = nil;
}
// Implement the "set" accessor rather than depending on #synthesize so that we can set up registration for context save notifications.
- (void)setManagedObjectContext:(NSManagedObjectContext *)aContext {
if (managedObjectContext) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:managedObjectContext];
}
managedObjectContext = aContext;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(managedObjectContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:managedObjectContext];
}
// When a managed object is first created, it has a temporary managed object ID. When the managed object context in which it was created is saved, the temporary ID is replaced with a permanent ID. The temporary IDs can no longer be used to retrieve valid managed objects. The cache handles the save notification by iterating through its cache nodes and removing any nodes with temporary IDs.
- (void)managedObjectContextDidSave:(NSNotification *)notification {
HowToCacheNode *cacheNode = nil;
NSMutableArray *keys = [NSMutableArray array];
for (NSString *key in cache) {
cacheNode = [cache objectForKey:key];
if ([cacheNode.objectID isTemporaryID]) {
[keys addObject:key];
}
}
[cache removeObjectsForKeys:keys];
}
- (NSEntityDescription *)howToCategoryEntityDescription {
if (howToCategoryEntityDescription == nil) {
howToCategoryEntityDescription = [NSEntityDescription entityForName:#"HowToCategory" inManagedObjectContext:managedObjectContext];
}
return howToCategoryEntityDescription;
}
static NSString * const kCategoryNameSubstitutionVariable = #"NAME";
- (NSPredicate *)categoryNamePredicateTemplate {
if (howToCategoryNamePredicateTemplate == nil) {
NSExpression *leftHand = [NSExpression expressionForKeyPath:#"name"];
NSExpression *rightHand = [NSExpression expressionForVariable:kCategoryNameSubstitutionVariable];
howToCategoryNamePredicateTemplate = [[NSComparisonPredicate alloc] initWithLeftExpression:leftHand rightExpression:rightHand modifier:NSDirectPredicateModifier type:NSLikePredicateOperatorType options:0];
}
return howToCategoryNamePredicateTemplate;
}
#define USE_CACHING // Undefine this macro to compare performance without caching
- (HowToCategory *)howToCategoryWithName:(NSString *)name {
NSTimeInterval before = [NSDate timeIntervalSinceReferenceDate];
#ifdef USE_CACHING
// check cache
HowToCacheNode *cacheNode = [cache objectForKey:name];
if (cacheNode != nil) {
cacheNode.accessCounter = accessCounter++; // cache hit, update access counter
HowToCategory *category = (HowToCategory *)[self.managedObjectContext objectWithID:cacheNode.objectID];
totalCacheHitCost += ([NSDate timeIntervalSinceReferenceDate] - before);
cacheHitCount++;
return category;
}
#endif
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; // cache missed, fetch from store - if not found in store there is no category object for the name and we must create one
[fetchRequest setEntity:self.howToCategoryEntityDescription];
NSLog(#"Fetch Request: %#",fetchRequest);
NSPredicate *predicate = [self.howToCategoryNamePredicateTemplate predicateWithSubstitutionVariables:[NSDictionary dictionaryWithObject:name forKey:kCategoryNameSubstitutionVariable]];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *fetchResults = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSAssert1(fetchResults != nil, #"Unhandled error executing fetch request in import thread: %#", [error localizedDescription]);
HowToCategory *category = nil;
if ([fetchResults count] > 0) {
category = [fetchResults objectAtIndex:0]; // get category from fetch
} else if ([fetchResults count] == 0) {
// category not in store, must create a new category object
category = [[HowToCategory alloc] initWithEntity:self.howToCategoryEntityDescription insertIntoManagedObjectContext:managedObjectContext];
category.name = name; //name
// Set the sort order for the category
if ([category.name isEqualToString:#"LB"]) {
category.order = [NSNumber numberWithInt:1];
} else if ([category.name isEqualToString:#"DP"]) {
category.order = [NSNumber numberWithInt:2];
} else if ([category.name isEqualToString:#"OP"]) {
category.order = [NSNumber numberWithInt:3];
}
}
#ifdef USE_CACHING
// add to cache
// first check to see if cache is full
if ([cache count] >= cacheSize) {
// evict least recently used (LRU) item from cache
NSUInteger oldestAccessCount = UINT_MAX;
NSString *key = nil, *keyOfOldestCacheNode = nil;
for (key in cache) {
HowToCacheNode *tmpNode = [cache objectForKey:key];
if (tmpNode.accessCounter < oldestAccessCount) {
oldestAccessCount = tmpNode.accessCounter;
keyOfOldestCacheNode = key;
}
}
// retain the cache node for reuse
cacheNode = [cache objectForKey:keyOfOldestCacheNode];
// remove from the cache
if (keyOfOldestCacheNode != nil)
[cache removeObjectForKey:keyOfOldestCacheNode];
} else {
// create a new cache node
cacheNode = [[HowToCacheNode alloc] init];
}
cacheNode.objectID = [category objectID];
cacheNode.accessCounter = accessCounter++;
[cache setObject:cacheNode forKey:name];
#endif
totalCacheMissCost += ([NSDate timeIntervalSinceReferenceDate] - before);
cacheMissCount++;
return category;
}
#end
I have an ordinary Database manager class. Here is the code:
#import "DatabaseManager.h"
#import "Tolo.h"
#import "Action.h"
#import "ActionCreatorConstants.h"
#import <sqlite3.h>
#import "DatabaseConstants.h"
#import "KGKSignal.h"
#interface DatabaseManager ()
#property (nonatomic, strong) NSString *documentsDirectory;
#property (nonatomic, strong) NSString *databaseFilename;
#property (nonatomic, strong) NSMutableArray *arrayResults;
#property (nonatomic, strong) NSMutableArray *arrayColumnNames;
#property (nonatomic) int affectedRows;
#property (nonatomic) long long lastInsertedRowID;
#end
#implementation DatabaseManager
static DatabaseManager *instance = nil;
+ (instancetype)getInstance {
if (instance == nil) {
instance = [[DatabaseManager alloc] initWithDatabaseFilename:DATABASE_NAME];
}
return instance;
}
- (instancetype)initWithDatabaseFilename:(NSString *)databaseFilename {
self = [super init];
if (self) {
REGISTER();
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
self.documentsDirectory = [paths objectAtIndex:0];
self.databaseFilename = databaseFilename;
// [self copyDatabaseIntoDocumentsDirectory];
}
return self;
}
- (void)copyDatabaseIntoDocumentsDirectory {
NSString *destinationPath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseFilename];
NSError *error;
[[NSFileManager defaultManager] copyItemAtPath:sourcePath
toPath:destinationPath
error:&error];
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}
}
- (void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable {
sqlite3 *sqlite3Database;
// NSString *databasePath = [self.documentsDirectory
// stringByAppendingPathComponent:self.databaseFilename];
NSString *databasePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:DATABASE_NAME];
if (self.arrayResults != nil) {
[self.arrayResults removeAllObjects];
self.arrayResults = nil;
}
self.arrayResults = [[NSMutableArray alloc] init];
if (self.arrayColumnNames != nil) {
[self.arrayColumnNames removeAllObjects];
self.arrayColumnNames = nil;
}
self.arrayColumnNames = [[NSMutableArray alloc] init];
BOOL openDatabaseResult = sqlite3_open([databasePath UTF8String], &sqlite3Database);
if (openDatabaseResult == SQLITE_OK) {
sqlite3_stmt *compiledStatement;
BOOL preparedStatementResult = sqlite3_prepare_v2(sqlite3Database, query, -1,
&compiledStatement, NULL);
if (preparedStatementResult == SQLITE_OK) {
if (!queryExecutable) {
NSMutableArray *arrayDataRow;
while (sqlite3_step(compiledStatement) == SQLITE_ROW) {
arrayDataRow = [[NSMutableArray alloc] init];
int totalColumns = sqlite3_column_count(compiledStatement);
for (int i = 0; i < totalColumns; i++) {
char *dbDataAsChars = (char *)sqlite3_column_text(compiledStatement, i);
if (dbDataAsChars != NULL) {
[arrayDataRow addObject:[NSString stringWithUTF8String:dbDataAsChars]];
}
if (self.arrayColumnNames.count != totalColumns) {
dbDataAsChars = (char *)sqlite3_column_name(compiledStatement, i);
[self.arrayColumnNames addObject:[NSString stringWithUTF8String:dbDataAsChars]];
}
}
if (arrayDataRow.count > 0) {
[self.arrayResults addObject:arrayDataRow];
}
}
} else {
BOOL executeQueryResult = sqlite3_step(compiledStatement);
if (executeQueryResult) {
self.affectedRows = sqlite3_changes(sqlite3Database);
self.lastInsertedRowID = sqlite3_last_insert_rowid(sqlite3Database);
} else {
NSLog(#"Database error: %s", sqlite3_errmsg(sqlite3Database));
}
}
} else {
NSLog(#"%s", sqlite3_errmsg(sqlite3Database));
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(sqlite3Database);
}
- (NSArray *)loadDataFromDatabase:(NSString *)query {
[self runQuery:[query UTF8String] isQueryExecutable:NO];
return (NSArray *)self.arrayResults;
}
- (void)executeQuery:(NSString *)query {
[self runQuery:[query UTF8String] isQueryExecutable:YES];
}
SUBSCRIBE(Action) {
if ([event.type isEqualToString:GET_LAST_SIGNAL_DATE_FROM_DATABASE]) {
NSLog(#"Lal");
}
}
- (void)insertSignal:(KGKSignal *)signal {
NSString *insertSignalQuery = [NSString stringWithFormat:#"INSERT INTO %# (%#,%#,%#,%#,%#,%#,%#,%#,%#,%#,%#,%#) VALUES (%ld,%ld,%f,%f,%ld,%f,%f,%ld,%ld,%ld,%ld,%ld);", TABLE_SIGNAL, COLUMN_DEVICE_ID, COLUMN_MODE, COLUMN_LATITUDE, COLUMN_LONGITUDE, COLUMN_DATE, COLUMN_VOLTAGE, COLUMN_BALANCE, COLUMN_SATELLITES, COLUMN_SPEED, COLUMN_CHARGE, COLUMN_DIRECTION, COLUMN_TEMPERATURE, (long)signal.deviceId, (long)signal.mode, signal.latitude, signal.longitude, (long)signal.date, signal.voltage, signal.balance, (long)signal.satellites, (long)signal.speed, (long)signal.charge, (long)signal.direction, (long)signal.temperature];
[self executeQuery:insertSignalQuery];
}
- (NSInteger)getLastSignalDate {
NSInteger lastSignalDate = 1441065600;
return lastSignalDate;
}
#end
The problem lurks in the last method - getLastSignalDate. When i set return value to 0 - app works ok. When method returns any non-null number - app craches in runtime (build successful). Error occurs in Tolo object - it can not register (Via REGISTER() macro) Database Manager object - EXC_BAD_ACCESS error in publish method of Tolo.m. Did someone face with same wierd behavior???
I've overriden dealloc method of Database Manager and it didn't log before error occured - so object exists in memory.
How to display an integer value in a UILabel in ViewDidLoad? I did for text and date and image but how to convert int to string. I was trying with following code
NSString* label=[aa stringWithFormat:#"%d",((Comments *) [self.list objectAtIndex:0]).noofcomm]];
[self.comments2 setText:label];
but didn't work.Please help me.How to set with the Integer with UILabel?
This is my comments.h
#interface Comments : NSObject
{
NSInteger iD;
UIImage *photo;
NSString *name;
NSString *descrp;
NSDate *date;
NSString *msg;
NSInteger noofcomm;
NSInteger nooflikes;
}
#property(nonatomic,assign)NSInteger iD;
#property(nonatomic,retain)UIImage *photo;
#property(nonatomic,retain)NSString *name;
#property(nonatomic,retain)NSString *descrp;
#property(nonatomic,strong)NSDate *date;
#property(nonatomic,retain)NSString *msg;
#property(nonatomic,assign)NSInteger noofcomm;
#property(nonatomic,assign)NSInteger nooflikes;
#end
DBClass.m
#import "DBClass.h"
#import "Comments.h"
#implementation DBClass
- (NSMutableArray *) getMyComments{
NSMutableArray *wineArray = [[NSMutableArray alloc] init];
#try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:#"ComntDB.sqlite"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
if(!success)
{
NSLog(#"Cannot locate database file '%#'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(#"An error has occured.");
}
const char *sql = "SELECT id, photo,name,descrp, time,msg,comments,likes FROM Com";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(#"Problem with prepare statement");
}
//
while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
Comments *MyWine = [[Comments alloc]init];
MyWine.iD = sqlite3_column_int(sqlStatement, 0);
const char *raw = sqlite3_column_blob(sqlStatement, 1);
int rawLen = sqlite3_column_bytes(sqlStatement, 1);
NSData *data = [NSData dataWithBytes:raw length:rawLen];
MyWine.photo = [[UIImage alloc] initWithData:data];
MyWine.name = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,2)];
MyWine.descrp = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 3)];
MyWine.date=[NSDate dateWithTimeIntervalSince1970:sqlite3_column_double(sqlStatement,4)];
MyWine.msg = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,5)];
MyWine.noofcomm = sqlite3_column_int(sqlStatement, 6);
MyWine.nooflikes = sqlite3_column_int(sqlStatement, 7);
[wineArray addObject:MyWine];
}
}
#catch (NSException *exception) {
NSLog(#"An exception occured: %#", [exception reason]);
}
#finally {
return wineArray;
}
}
#end
RootViewController.m
#import "RootViewController.h"
#import "Comments.h"
#import "DBClass.h"
#interface RootViewController ()
#end
#implementation RootViewController
#synthesize list;
#synthesize image2;
#synthesize name2;
#synthesize descrp2;
#synthesize msg2;
#synthesize date2;
#synthesize comments2;
#synthesize likes2;
- (void)viewDidLoad
{
DBClass * mywines =[[DBClass alloc] init];
self.list = [mywines getMyComments];
[self.image2 setImage:((Comments *) [self.list objectAtIndex:0]).photo];
[self.name2 setText:((Comments *) [self.list objectAtIndex:0]).name];
[self.descrp2 setText:((Comments *) [self.list objectAtIndex:0]).descrp];
NSDateFormatter* fmtr = [[NSDateFormatter alloc] init];
[fmtr setDateFormat:#"MM/dd/yy"];
NSString* label_str = [fmtr stringFromDate:((Comments *) [self.list objectAtIndex:0]).date];
[self.date2 setText:label_str];
[self.msg2 setText:((Comments *) [self.list objectAtIndex:0]).msg];
//[self.comments2 setText:((Comments *) [self.list objectAtIndex:0]).noofcomm];
// int solution = 1;
// [self.comments2 setText:[NSString stringWithFormat:#"%d", solution]];
// int solution2 = 1;
// [self.likes2 setText:[NSString stringWithFormat:#"%d", solution2]];
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setImage2:nil];
[self setName2:nil];
[self setMsg2:nil];
[self setDescrp2:nil];
[self setComments2:nil];
[self setLikes2:nil];
[self setDate2:nil];
[super viewDidUnload];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
NSInteger someInteger = myInteger;
NSString *someString = [NSString stringWithFormat:#"%d", someInteger];
myLabel.text = someString;
or
NSNumber *someNumber = #(myInteger);
NSString *someString = [someNumber stringValue];
myLabel.text = someString;
Both will work.
EDIT:
In your case, it will be something like this:
NSInteger someInteger = ((Comments *) [self.list objectAtIndex:0]).noofcomm;
NSString someString = [NSString stringWithFormat:#"%d", someInteger];
self.comments2.text = someString;
If it's still not working, FOR SURE the problem is somewhere else, and not with the conversion. Check with property noofcomm has a valid value, check if your label reference is ok (test with a random value before the conversion), and somethings like that.
You need to build an NSString
int someInteger = 10;
NSString *someString = [[NSString alloc] initWithFormat:#"%d", someInteger];
You can use something like [NSString string_from_int:42] in LCategory since 0.1.3: https://github.com/superarts/LCategory
_lbl_yourLabel.text=[NSString stringWithFormat:#"%d",[[dic valueForKey:#"your integer value"] intValue]];
On the top left is your label named "yourLabel" , "dic" is your json response dictionary where all the data is coming in key value terms, "your integer value" is the key for which the value will be assign to the label "yourLabel", we have taken intValue because we cannot assign integer value directly to the label.
or you also can try below:
int anyInteger = 13;
NSString *yourString = [[NSString alloc] initWithFormat:#"%d", anyInteger];
self.yourLabel.text = yourString;