I have a ContentPageViewController class, it has the IBOutlet stuff. I write my getter of ContentPageViewController in the ViewController like the following code.
ContentPageViewController.h
#interface ContentPageViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *busName;
#property (weak, nonatomic) IBOutlet UILabel *busTime;
#property (weak, nonatomic) IBOutlet UILabel *busType;
#end
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// instantiation from a storyboard
ContentPageViewController *page = [self.storyboard instantiateViewControllerWithIdentifier:#"ContentPageViewController"];
self.page = page;
// send url request
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://api.apb-shuttle.info/now" ]];
[self sendURLRequest:request];
// add the view of ContendPageViewController into ViewController
[self.view addSubview:self.page.view];
}
// It works if i remove the following code
- (ContentPageVC *)page
{
if (_page) _page = [[ContentPageViewController alloc] init];
return _page;
}
Nothing happened when I updated it. And it gave me a nil.
- (void)updateUI
{
// I got null here
NSLog("%#", self.page.busName)
// The spacing style font
NSDictionary *titleAttributes = #{
NSKernAttributeName: #10.0f
};
NSDictionary *attributes = #{
NSKernAttributeName: #5.0f
};
self.page.busName.attributedText = [[NSMutableAttributedString alloc] initWithString:bus.name
attributes:titleAttributes];
self.page.busTime.attributedText = [[NSMutableAttributedString alloc] initWithString:bus.depart
attributes:titleAttributes];
self.page.busType.attributedText = [[NSMutableAttributedString alloc] initWithString:bus.note
attributes:attributes];
}
The following code is when I called the updateUI:
- (void)sendURLRequest:(NSURLRequest *)requestObj
{
isLoading = YES;
[RequestHandler PerformRequestHandler:requestObj withCompletionHandler:^(NSDictionary *data, NSError *error) {
if (!error) {
bus = [JSONParser JSON2Bus:data];
// Add the bus object into the array.
[self.busArray addObject: bus];
[[NSOperationQueue mainQueue] addOperationWithBlock: ^{
[self updateUI];
isLoading = NO;
}];
} else {
NSLog(#"%#", [error localizedDescription]);
}
}];
}
But it worked if I removed the getter above.
I have no idea how it works, please give me some hint. Thanks.
Check your IBOutlet is connected.
Check the method you are calling isn't called before the view is created from the storyboard/nib
EDIT
The lines of code that you added, are overriding your getter. And every time you call self.page, your creating a new instance!
// It works if i remove the following code
- (ContentPageVC *)page
{
if (_page) _page = [[ContentPageViewController alloc] init];
return _page;
}
It should be like so:
// It works if i remove the following code
- (ContentPageVC *)page
{
if (!_page) _page = [[ContentPageViewController alloc] init]; // Added the ! mark, only if nil you would create a new instance.
return _page;
}
Plus you are calling alloc init on it, so Its not the same instance from storyboard!
So you should do this:
- (ContentPageVC *)page
{
if (!_page) _page = [self.storyboard instantiateViewControllerWithIdentifier:#"ContentPageViewController"];
return _page;
}
And remove this lines of code:
// instantiation from a storyboard
ContentPageViewController *page = [self.storyboard instantiateViewControllerWithIdentifier:#"ContentPageViewController"];
self.page = page;
Every time you call "self.page" the override getter function will call. and return the same instance.
Have a question about blocks in objective-c.
For example I have a list of actions.
I'm initializing an array of blocks:
self.actions = #[
^() { [self showObject:self.object_1]; },
^() { [self showObject:self.object_2]; },
^() { [self showObject:self.object_3]; }
];
And calling them when some row is pressed:
- (void)pressedRowAtIndex:(NSInteger)index {
if (index < actions.count) {
void (^action)() = [actions objectAtIndex:index];
if (action != nil) {
action();
}
}
}
And all works fine without problem. But when I init my actions array by using initWithObjects method:
self.actions = [NSArray alloc] initWithObjects:
^() { [self showObject:self.object_1]; },
^() { [self showObject:self.object_2]; },
^() { [self showObject:self.object_3]; },
nil
];
Than I get crash trying to get action by index by using objectAtIndex method of NSArray class.
I understand the difference between this inits. First one don't increase reference count like first do. But can someone explain why it crash?
Edit:
All that I've found. Maybe I'm nub and somewhere else is another useful information.
There is no crash info in terminal:
Code for Onik IV:
Small example:
#interface ViewController () {
NSArray *actions;
}
#property (nonatomic, strong) NSString *object1;
#property (nonatomic, strong) NSString *object2;
#property (nonatomic, strong) NSString *object3;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
actions = [[NSArray alloc] initWithObjects:
^() { [self showObject:self.object1];},
^() { [self showObject:self.object2]; },
^() {[self showObject:self.object3]; },
nil];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.object1 = #"object 1";
self.object2 = #"object 2";
self.object3 = #"object 3";
void(^firsSimpleBlock)(void) = [actions lastObject];
firsSimpleBlock();
void(^simpleBlock)(void) = [actions firstObject];
simpleBlock();
}
-(void)showObject:(NSString *)object
{
NSLog(#"Show: %#",object);
}
#end
Try something like this.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
(^someBlock)(void) = ^void(void){
self.object1;
};
actions = [[NSArray alloc] initWithObjects:
[someBlock copy],
[someOtherBlock copy],
[anotherBlock copy],
nil];
}
Blocks are allocated on the stack and are therefor removed when the frame is removed from the stack leading to sail pointers for all pointers pointing to that block. When you allocate a object with the literal "#" sign the object is allocated in a pool so all literals that are the "same" point to the same instance and are never deallocated.
NSString *a = #"A";
NSString *b = #"A";
points to the same instance of a string, while:
NSString *a = [NSString stringWithFormat:#"A"];
NSString *b = [NSString stringWithFormat:#"A"];
are two different objects.
So it works when you are creating a literal array but when you add the blocks dynamically they will be removed when its time to use them therefor the BAD_ACCESS. Solution is to send "copy" message to the block that will copy it to the heap and the block will not be released.
It´s the same, you must have another kind of problem (sintax?).
Try this:
#interface ViewController ()
#property (nonatomic, strong) NSString *object1;
#property (nonatomic, strong) NSString *object2;
#property (nonatomic, strong) NSString *object3;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.object1 = #"object 1";
self.object2 = #"object 2";
self.object3 = #"object 3";
NSArray *actions = #[^() { [self showObject:self.object1];},
^() { [self showObject:self.object2]; },
^() {[self showObject:self.object3]; }
];
NSArray *secondActions = [[NSArray alloc] initWithObjects:
^() { [self showObject:self.object1];},
^() { [self showObject:self.object2]; },
^() { [self showObject:self.object3];},
nil
];
void(^firsSimpleBlock)(void) = [actions lastObject];
firsSimpleBlock();
void(^simpleBlock)(void) = [secondActions firstObject];
simpleBlock();
}
-(void)showObject:(NSString *)object
{
NSLog(#"Show: %#",object);
}
#end
i decided to create a simple FileBrowser using UITableViewController with delegate which detect the file you chosen,
and i presented the UITableViewController like that
fbVC = [[FileBrowserTableViewController alloc] init];
fbVC.delegate = self;
fbVC.path = #"/";
navigationController = [[UINavigationController alloc] initWithRootViewController:fbVC];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
and added the delegate method in the other class
- (void)fileBrowser:(FileBrowserTableViewController *)fileBrowser didFinishWithFileURL:(NSURL *)fileURLPath {
NSString *extString = [fileURLPath absoluteString];
NSString *ext = [[extString pathExtension] lowercaseString];
NSString* theFileName = [[extString lastPathComponent] stringByDeletingPathExtension];
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)fileURLPath.pathExtension, NULL);
CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType);
NSString *MIMETypeString = (__bridge NSString*)MIMEType;
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"FileBrowser" message:[NSString stringWithFormat:#"---URL : %# --FileName : %# --ext %#: mimetype : %#", fileURLPath, theFileName, fileURLPath.pathExtension, MIMETypeString] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
[self.companion sendDocumentsAtPath:fileURLPath fileName:[NSString stringWithFormat:#"[TGEnhancer]%#.%#",theFileName, fileURLPath.pathExtension] mimeType:MIMETypeString];
// [fileBrowser.navigationController popViewControllerAnimated:YES];
[fileBrowser.navigationController dismissViewControllerAnimated:YES completion:^{
NSLog(#"File Browser - Finished");
}];
}
but for some reason the delegate works only from the first page of UINavigationController
here is my .h file
#protocol FileBrowserTableViewControllerDelegate;
#interface FileBrowserTableViewController : UITableViewController
{
NSString *path;
NSMutableArray *files;
}
#property (nonatomic,retain) NSString *path;
#property (nonatomic,retain) NSMutableArray *files;
#property (nonatomic, strong) id<FileBrowserTableViewControllerDelegate> delegate;
#end
#protocol FileBrowserTableViewControllerDelegate <NSObject>
#optional
- (void)fileBrowser:(FileBrowserTableViewController *)fileBrowser didFinishWithFileURL:(NSURL *)fileURLPath;
- (void)fileBrowserDidCancel:(FileBrowserTableViewController *)fileBrowser;
#end
my didSelectRowAtIndexPath method here
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
File *aFile = [files objectAtIndex:indexPath.row];
if(aFile.isDirectory)
{
FileBrowserTableViewController *anotherViewController = [[FileBrowserTableViewController alloc] init];
anotherViewController.path = [path stringByAppendingPathComponent:aFile.name];
[self.navigationController pushViewController:anotherViewController animated:YES];
} else {
[self doOpenFileAtIndexPath:indexPath];
}
}
- (void)doOpenFileAtIndexPath:(NSIndexPath*)indexPath {
// File *aFile = [files objectAtIndex:indexPath.row];
[self openFileAtIndexPath:indexPath];
}
- (void)openFileAtIndexPath:(NSIndexPath*)indexPath
{
File *aFile = [files objectAtIndex:indexPath.row];
NSString *extension = [[aFile.name pathExtension] lowercaseString];
NSString *fullpath = [path stringByAppendingPathComponent:aFile.name];
NSURL *filePathUrl = [NSURL fileURLWithPath:fullpath];
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:#"Type Existe"
message:[NSString stringWithFormat:#"--Name : %# Fullpath : %#", aFile.name, fullpath]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
[self.delegate fileBrowser:self didFinishWithFileURL:filePathUrl];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
anyone can help me and tell me What exactly make delegate works (once) within UINavigationController ? specially from the first path only ( if i open another path and choose a file, it won't work.
Thanks
OPs i think i find the solution by myself, my mistake was in didSelectRowAtIndexPath method
i wasn't calling the delegate again.
here the code worked for me
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
File *aFile = [files objectAtIndex:indexPath.row];
if(aFile.isDirectory)
{
FileBrowserTableViewController *anotherViewController = [[FileBrowserTableViewController alloc] init];
anotherViewController.path = [path stringByAppendingPathComponent:aFile.name];
anotherViewController.delegate = self.delegate;
[self.navigationController pushViewController:anotherViewController animated:YES];
} else {
[self doOpenFileAtIndexPath:indexPath];
}
}
Thanks again.. hope it helps others..
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.item > 0 )
{
myNumber = indexPath.item;
NSLog(#"Item is %i", myNumber);
NSString *myNewString = [#(myNumber) stringValue];
[txt setText:myNewString];
self.datastring=txt.text;
WeddingViewController *wed=[[WeddingViewController alloc]init];
[self presentViewController:wed animated:YES completion:nil];
}
}
and in the viewDidLoad of second collection view.....
- (void)viewDidLoad
{
[super viewDidLoad];
self.lbl.text =self.datastring;
}
You could create a custom constructor (init) method for your WeddingViewController like this along with a property to hold that value:
Inside your WeddingViewController.h file, create the constructor method:
#property (nonatomic, assign) int storedIntValue;
-(id)initWithValue:(int)intValue;
Then in your implementation file, you can go:
-(id)initWithValue:(int)intValue
{
self = [super init];
if(self)
{
self.storedIntValue = intValue;
}
return self;
}
-(void)viewDidLoad
{
....
self.lbl.text = [[NSString alloc] initWithFormat:#"%d", self.storedIntValue];
}
Finally, where you push the WeddingViewController, you can go:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.item > 0 )
{
myNumber = indexPath.item;
NSLog(#"Item is %i", myNumber);
NSString *myNewString = [#(myNumber) stringValue];
[txt setText:myNewString];
self.datastring=txt.text;
// ----------------------------------------------------
// Notice use of the "initWithIntValue:" method
//
// note: is myNumber meant to be indexPath row ?
// ----------------------------------------------------
WeddingViewController *wed=[[WeddingViewController alloc] initWithValue:myNumber];
[self presentViewController:wed animated:YES completion:nil];
}
}
Otherwise, the alternative is to store that int value somewhere in your application that can be accessed globally, such as a singleton, or if it's a user defaults thing, you can use:
// save value into NSUserDefaults if it's appropriate
[[NSUserDefaults standardDefaults] setValue:[NSNumber numberWithInt:3] forKey:#"myIntValue"];
[NSUserDefaults synchronize];
// get value from NSUserDefaults
int myIntValue = [[[NSUserDefaults standardDefaults] valueForKey:#"myIntValue"] integerValue];
Does that help?
you have to do this way,you can make string property in WeddingViewController.h and acccess it in viewDidLoad direct ,
#property (nonatomic, assign) NSString dataString;
and in viewWillAppear
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.lbl.text = dataString;
}
and when make WeddingViewController object give property like this,
WeddingViewController *wed=[[WeddingViewController alloc]init];
wed.dataString = dataString;
[self presentViewController:wed animated:YES completion:nil];
When a user run my app for the first time a LoginViewController appears. Once he is logged in, I present a ModalViewController with all the stuff of the app. If the user want to log out, I dismiss the modal view, showing the LoginViewController again.
The problem comes if the user runs the app when is already logged. In the self.window.rootViewController, I set directly the main view of the app (embebed in a UITabBarController), so if the user want to log out, I don't know the way to "dismiss" the view and show the LoginViewController.
SCENARIO:
User no logged yet: LoginViewController -> (Log in) -> UITabBarController -> (Log out) -> LoginViewController.
User already logged: UITabBarController -> (Log out) -> LoginViewController.
I think there must be a simple way to do this, because it is a very normal behavior in an app with a login system, but I haven't found a clean way to do it.
After struggling with this many times, we published an open source library called CLHoppingViewController which handles exactly this kind of scenarios.
So, in your case, you would do something like this to describe the start up flow:
UIViewController *loginViewController;
UIViewController *mainViewController;
if (user_not_logged_in) {
[self hopToViewController:loginViewController then:^{
[self hopToViewController:mainViewController then:nil];
}];
}
else {
[self hopToViewController:mainViewController then:nil];
}
The library can support much more advanced conditional sequences. For example, you can display a splash screen, conditionally show onboarding UX, etc.
There's a short tutorial here.
Try following way :
TabBarController *tabBarController1 = [[TabBarController alloc] init];
self.window.rootViewController = tabBarController1.myTabBarController;
[self.window makeKeyAndVisible];
// if not Logedin
if() {
self.viewController = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
[self.tabBarController1 presentModalViewController:navController animated:NO];
}
After Login, dismiss LoginViewController. Again while logout present LoginViewController modally on tabBarViewController as above.
I did this:
App Delegate:
if() //signed in
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
TabBarController *tabBarController1 = [[TabBarController alloc] init];
self.window.rootViewController = tabBarController1.myTabBarController;
[self.window makeKeyAndVisible];
}
else //signed out
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[SigninTabBarTemplateViewController alloc] initWithNibName:#"SigninTabBarTemplateViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
}
If you are signed out, I implement the tabbarcontroller as a separate UITabBarController like that:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
UIViewController *viewController1 = [[FirstTab alloc] initWithNibName:#"FirstTab" bundle:NSBundle.mainBundle];
UINavigationController *firstNavController = [[UINavigationController alloc]initWithRootViewController:viewController1];
UIViewController *viewController2 = [[SecondTab alloc] initWithNibName:#"SecondTab" bundle:NSBundle.mainBundle];
UINavigationController *secondNavController = [[UINavigationController alloc]initWithRootViewController:viewController2];
myTabBarController = [[UITabBarController alloc] init];
myTabBarController.viewControllers = [NSArray arrayWithObjects:firstNavController, secondNavController, nil];
}
return self;
}
An elegant way to handle login states is to use a statemachine. The principle is, to define all possible states and the transitions between them. This might seem like an overkill on the first look, but as larger as your app grows, this investment will pay off.
For small apps, the if/else way should be fine.
#import <UIKit/UIKit.h>
#import "EditInfoViewController.h"
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, EditInfoViewControllerDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tblPeople;
- (IBAction)addNewRecord:(id)sender;
#end
#import "ViewController.h"
#import "DBManager.h"
#interface ViewController ()
#property (nonatomic, strong) DBManager *dbManager;
#property (nonatomic, strong) NSArray *arrPeopleInfo;
#property (nonatomic) int recordIDToEdit;
-(void)loadData;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Make self the delegate and datasource of the table view.
self.tblPeople.delegate = self;
self.tblPeople.dataSource = self;
// Initialize the dbManager property.
self.dbManager = [[DBManager alloc] initWithDatabaseFilename:#"sampledb.sql"];
// Load the data.
[self loadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
EditInfoViewController *editInfoViewController = [segue destinationViewController];
editInfoViewController.delegate = self;
editInfoViewController.recordIDToEdit = self.recordIDToEdit;
}
#pragma mark - IBAction method implementation
- (IBAction)addNewRecord:(id)sender {
// Before performing the segue, set the -1 value to the recordIDToEdit. That way we'll indicate that we want to add a new record and not to edit an existing one.
self.recordIDToEdit = -1;
// Perform the segue.
[self performSegueWithIdentifier:#"idSegueEditInfo" sender:self];
}
#pragma mark - Private method implementation
-(void)loadData{
// Form the query.
NSString *query = #"select * from peopleInfo";
// Get the results.
if (self.arrPeopleInfo != nil) {
self.arrPeopleInfo = nil;
}
self.arrPeopleInfo = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];
// Reload the table view.
[self.tblPeople reloadData];
}
#pragma mark - UITableView method implementation
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.arrPeopleInfo.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// Dequeue the cell.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"idCellRecord" forIndexPath:indexPath];
NSInteger indexOfFirstname = [self.dbManager.arrColumnNames indexOfObject:#"firstname"];
NSInteger indexOfLastname = [self.dbManager.arrColumnNames indexOfObject:#"lastname"];
NSInteger indexOfAge = [self.dbManager.arrColumnNames indexOfObject:#"age"];
// Set the loaded data to the appropriate cell labels.
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", [[self.arrPeopleInfo objectAtIndex:indexPath.row] objectAtIndex:indexOfFirstname], [[self.arrPeopleInfo objectAtIndex:indexPath.row] objectAtIndex:indexOfLastname]];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Age: %#", [[self.arrPeopleInfo objectAtIndex:indexPath.row] objectAtIndex:indexOfAge]];
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 60.0;
}
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
// Get the record ID of the selected name and set it to the recordIDToEdit property.
self.recordIDToEdit = [[[self.arrPeopleInfo objectAtIndex:indexPath.row] objectAtIndex:0] intValue];
// Perform the segue.
[self performSegueWithIdentifier:#"idSegueEditInfo" sender:self];
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the selected record.
// Find the record ID.
int recordIDToDelete = [[[self.arrPeopleInfo objectAtIndex:indexPath.row] objectAtIndex:0] intValue];
// Prepare the query.
NSString *query = [NSString stringWithFormat:#"delete from peopleInfo where peopleInfoID=%d", recordIDToDelete];
// Execute the query.
[self.dbManager executeQuery:query];
// Reload the table view.
[self loadData];
}
}
#pragma mark - EditInfoViewControllerDelegate method implementation
-(void)editingInfoWasFinished{
// Reload the data.
[self loadData];
}
#end
===================
#import <UIKit/UIKit.h>
#protocol EditInfoViewControllerDelegate
-(void)editingInfoWasFinished;
#end
#interface EditInfoViewController : UIViewController <UITextFieldDelegate>
#property (nonatomic, strong) id<EditInfoViewControllerDelegate> delegate;
#property (weak, nonatomic) IBOutlet UITextField *txtFirstname;
#property (weak, nonatomic) IBOutlet UITextField *txtLastname;
#property (weak, nonatomic) IBOutlet UITextField *txtAge;
#property (nonatomic) int recordIDToEdit;
- (IBAction)saveInfo:(id)sender;
#end
#import "EditInfoViewController.h"
#import "DBManager.h"
#interface EditInfoViewController ()
#property (nonatomic, strong) DBManager *dbManager;
-(void)loadInfoToEdit;
#end
#implementation EditInfoViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// Make self the delegate of the textfields.
self.txtFirstname.delegate = self;
self.txtLastname.delegate = self;
self.txtAge.delegate = self;
// Set the navigation bar tint color.
self.navigationController.navigationBar.tintColor = self.navigationItem.rightBarButtonItem.tintColor;
// Initialize the dbManager object.
self.dbManager = [[DBManager alloc] initWithDatabaseFilename:#"sampledb.sql"];
// Check if should load specific record for editing.
if (self.recordIDToEdit != -1) {
// Load the record with the specific ID from the database.
[self loadInfoToEdit];
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#pragma mark - UITextFieldDelegate method implementation
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
#pragma mark - IBAction method implementation
- (IBAction)saveInfo:(id)sender {
// Prepare the query string.
// If the recordIDToEdit property has value other than -1, then create an update query. Otherwise create an insert query.
NSString *query;
if (self.recordIDToEdit == -1) {
query = [NSString stringWithFormat:#"insert into peopleInfo values(null, '%#', '%#', %d)", self.txtFirstname.text, self.txtLastname.text, [self.txtAge.text intValue]];
}
else{
query = [NSString stringWithFormat:#"update peopleInfo set firstname='%#', lastname='%#', age=%d where peopleInfoID=%d", self.txtFirstname.text, self.txtLastname.text, self.txtAge.text.intValue, self.recordIDToEdit];
}
// Execute the query.
[self.dbManager executeQuery:query];
// If the query was successfully executed then pop the view controller.
if (self.dbManager.affectedRows != 0) {
NSLog(#"Query was executed successfully. Affected rows = %d", self.dbManager.affectedRows);
// Inform the delegate that the editing was finished.
[self.delegate editingInfoWasFinished];
// Pop the view controller.
[self.navigationController popViewControllerAnimated:YES];
}
else{
NSLog(#"Could not execute the query.");
}
}
#pragma mark - Private method implementation
-(void)loadInfoToEdit{
// Create the query.
NSString *query = [NSString stringWithFormat:#"select * from peopleInfo where peopleInfoID=%d", self.recordIDToEdit];
// Load the relevant data.
NSArray *results = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];
// Set the loaded data to the textfields.
self.txtFirstname.text = [[results objectAtIndex:0] objectAtIndex:[self.dbManager.arrColumnNames indexOfObject:#"firstname"]];
self.txtLastname.text = [[results objectAtIndex:0] objectAtIndex:[self.dbManager.arrColumnNames indexOfObject:#"lastname"]];
self.txtAge.text = [[results objectAtIndex:0] objectAtIndex:[self.dbManager.arrColumnNames indexOfObject:#"age"]];
}
#end
=====
===================
#import <Foundation/Foundation.h>
#interface DBManager : NSObject
#property (nonatomic, strong) NSMutableArray *arrColumnNames;
#property (nonatomic) int affectedRows;
#property (nonatomic) long long lastInsertedRowID;
-(instancetype)initWithDatabaseFilename:(NSString *)dbFilename;
-(NSArray *)loadDataFromDB:(NSString *)query;
-(void)executeQuery:(NSString *)query;
#end
#import "DBManager.h"
#import <sqlite3.h>
#interface DBManager()
#property (nonatomic, strong) NSString *documentsDirectory;
#property (nonatomic, strong) NSString *databaseFilename;
#property (nonatomic, strong) NSMutableArray *arrResults;
-(void)copyDatabaseIntoDocumentsDirectory;
-(void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable;
#end
#implementation DBManager
#pragma mark - Initialization
-(instancetype)initWithDatabaseFilename:(NSString *)dbFilename{
self = [super init];
if (self) {
// Set the documents directory path to the documentsDirectory property.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
self.documentsDirectory = [paths objectAtIndex:0];
// Keep the database filename.
self.databaseFilename = dbFilename;
// Copy the database file into the documents directory if necessary.
[self copyDatabaseIntoDocumentsDirectory];
}
return self;
}
#pragma mark - Private method implementation
-(void)copyDatabaseIntoDocumentsDirectory{
// Check if the database file exists in the documents directory.
NSString *destinationPath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
// The database file does not exist in the documents directory, so copy it from the main bundle now.
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseFilename];
NSError *error;
[[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:destinationPath error:&error];
// Check if any error occurred during copying and display it.
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}
}
-(void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable{
// Create a sqlite object.
sqlite3 *sqlite3Database;
// Set the database file path.
NSString *databasePath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
// Initialize the results array.
if (self.arrResults != nil) {
[self.arrResults removeAllObjects];
self.arrResults = nil;
}
self.arrResults = [[NSMutableArray alloc] init];
// Initialize the column names array.
if (self.arrColumnNames != nil) {
[self.arrColumnNames removeAllObjects];
self.arrColumnNames = nil;
}
self.arrColumnNames = [[NSMutableArray alloc] init];
// Open the database.
BOOL openDatabaseResult = sqlite3_open([databasePath UTF8String], &sqlite3Database);
if(openDatabaseResult == SQLITE_OK) {
// Declare a sqlite3_stmt object in which will be stored the query after having been compiled into a SQLite statement.
sqlite3_stmt *compiledStatement;
// Load all data from database to memory.
BOOL prepareStatementResult = sqlite3_prepare_v2(sqlite3Database, query, -1, &compiledStatement, NULL);
if(prepareStatementResult == SQLITE_OK) {
// Check if the query is non-executable.
if (!queryExecutable){
// In this case data must be loaded from the database.
// Declare an array to keep the data for each fetched row.
NSMutableArray *arrDataRow;
// Loop through the results and add them to the results array row by row.
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Initialize the mutable array that will contain the data of a fetched row.
arrDataRow = [[NSMutableArray alloc] init];
// Get the total number of columns.
int totalColumns = sqlite3_column_count(compiledStatement);
// Go through all columns and fetch each column data.
for (int i=0; i<totalColumns; i++){
// Convert the column data to text (characters).
char *dbDataAsChars = (char *)sqlite3_column_text(compiledStatement, i);
// If there are contents in the currenct column (field) then add them to the current row array.
if (dbDataAsChars != NULL) {
// Convert the characters to string.
[arrDataRow addObject:[NSString stringWithUTF8String:dbDataAsChars]];
}
// Keep the current column name.
if (self.arrColumnNames.count != totalColumns) {
dbDataAsChars = (char *)sqlite3_column_name(compiledStatement, i);
[self.arrColumnNames addObject:[NSString stringWithUTF8String:dbDataAsChars]];
}
}
// Store each fetched data row in the results array, but first check if there is actually data.
if (arrDataRow.count > 0) {
[self.arrResults addObject:arrDataRow];
}
}
}
else {
// This is the case of an executable query (insert, update, ...).
// Execute the query.
BOOL executeQueryResults = sqlite3_step(compiledStatement);
if (executeQueryResults == SQLITE_DONE) {
// Keep the affected rows.
self.affectedRows = sqlite3_changes(sqlite3Database);
// Keep the last inserted row ID.
self.lastInsertedRowID = sqlite3_last_insert_rowid(sqlite3Database);
}
else {
// If could not execute the query show the error message on the debugger.
NSLog(#"DB Error: %s", sqlite3_errmsg(sqlite3Database));
}
}
}
else {
// In the database cannot be opened then show the error message on the debugger.
NSLog(#"%s", sqlite3_errmsg(sqlite3Database));
}
// Release the compiled statement from memory.
sqlite3_finalize(compiledStatement);
}
// Close the database.
sqlite3_close(sqlite3Database);
}
#pragma mark - Public method implementation
-(NSArray *)loadDataFromDB:(NSString *)query{
// Run the query and indicate that is not executable.
// The query string is converted to a char* object.
[self runQuery:[query UTF8String] isQueryExecutable:NO];
// Returned the loaded results.
return (NSArray *)self.arrResults;
}
-(void)executeQuery:(NSString *)query{
// Run the query and indicate that is executable.
[self runQuery:[query UTF8String] isQueryExecutable:YES];
}
#end
enter code here
#interface ViewController ()
{ sqlite3 *dbref;
NSString *dbpath;
BOOL flag;}
#end
#implementation ViewController
#synthesize usertxt,passtxt;
- (void)viewDidLoad
{[super viewDidLoad];
NSString *docpath;
NSError *error;
NSArray *docarr=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSLog(#"directory path=%#",docarr);
docpath=[docarr objectAtIndex:0];
// docpath=[docpath stringByAppendingString:#"/simpledb.sqlite/"];
[[NSFileManager defaultManager] createDirectoryAtPath:docpath withIntermediateDirectories:YES attributes:nil error:&error];
dbpath=[[NSString alloc] initWithString:[docpath stringByAppendingString:#"/simpledb.sqlite"]];
NSFileManager *fmgr=[NSFileManager defaultManager];
if([fmgr fileExistsAtPath:dbpath]!=YES)
{ char *err;
const char *dbp=[dbpath UTF8String];
if(sqlite3_open(dbp, &dbref)==SQLITE_OK)
{ const char *crstmt = "CREATE TABLE IF NOT EXISTS Login(Login_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,Username TEXT , Password TEXT)";
if(sqlite3_exec(dbref, crstmt, NULL, NULL,&err)!= SQLITE_OK)
{
}
sqlite3_close(dbref);
}}
// Do any additional setup after loading the view, typically from a nib.
}
-(IBAction)save:(id)sender
{[self validation];
if(flag==0)
{ sqlite3_stmt *statement;
NSString *insertSQL = [NSString stringWithFormat:#"insert into Login(Username,Password) values('%#','%#')",usertxt.text,passtxt.text];
const char *insert_stmt = [insertSQL UTF8String];
const char *dbp=[dbpath UTF8String];
if(sqlite3_open(dbp, &dbref)==SQLITE_OK)
{ sqlite3_prepare_v2(dbref, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
}
else
{
}}
sqlite3_finalize(statement);
sqlite3_close(dbref);
UIAlertView *objalert=[[UIAlertView alloc]initWithTitle:#"Inserted Successfully" message:nil delegate:nil cancelButtonTitle:#"cancel" otherButtonTitles:#"ok", nil];
[objalert show];
}}
-(IBAction)update:(id)sender
{ NSString *querySQL = [NSString stringWithFormat: #"update Login set Username='%#',Password='%#' where Login_id==1",usertxt.text,passtxt.text];
[self updateQuery:querySQL];}
-(BOOL)updateQuery:(NSString *)querySQL
{ sqlite3_stmt *statement;
const char *dbp=[dbpath UTF8String];
if(sqlite3_open(dbp, &dbref)==SQLITE_OK)
{ const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(dbref, query_stmt, -1, &statement, NULL) == SQLITE_OK)
{ if (sqlite3_step(statement) == SQLITE_ROW)
{ sqlite3_reset(statement);
return YES;
} }
sqlite3_finalize(statement);
sqlite3_close(dbref)}
else
{ return NO;
}
return YES}
-(void)validation
{ NSString *valida;
// usertxt.text = [usertxt.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
// passtxt.text = [passtxt.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([usertxt.text length]<2)
{flag=1;
valida=#"user Name : Minimum 2 Character req*\n";
UIAlertView *objalert=[[UIAlertView alloc]initWithTitle:nil message:valida delegate:nil cancelButtonTitle:nil otherButtonTitles:#"ok", nil];
[objalert show];
}
}
#imp flipsideviewcont
#syn entries
-(void)viewdidload
{
entries=[[nsmutablarray alloc]onit];
[self opendb];
nsstring *sql=[nsstring stringwithormat:#"select * from summery"];
sqlite_state *stat;
if(sqlite_prepare_v2(db,[sql utf8string],-1,&stat,nil)==sqlite_ok)
{while(sqlite_step(stat==sqlite_row))
{
char *field1=(char*)sqlite_column_text(stat,0);
nsstring *field1str=[[nsstring alloc]initwithutf8string:feild1];
char *field2=(char*)sqlite_column_text(stat,1);
nsstring *field2str=[[nsstring alloc]initwithutf8string:feild2];
nsstring *str=[[nsstring alloc]initwithformat:#"%#/%#-%#",field2str,field3str,field4str];
[entries addobjects:str];
}
-(nsstring*)filepath
{
nsarray *path=nssearchpathfordocumentry(nsdocumentdic,nsdomainmask,yes);
return([path objectAtindex:0]stringbyappingpathcomp:#"ss.sql");
}
-(void)opendb
{
if(sqlite_open([self filepath]utf8string,&db)!=sqlite_ok)
{sqlite_close(db);
nsasser(0,#"problem");
else
{
nslog(#"db open");
}
}
-(ibaction)done
{
[self.delegate flipsideviewcontrollerdidfinish :self];
}
cellforindex
{
cell.textlabel.text=[self.entries objectAtindex:indexpath:row];
}
===========================interface flipsideviewcont======
#import "sqlite3.h"
#class flipsideviewcontroller;
-(void)flipsideviewcontdidfinish:(flipsideviewcontroller*)controller;
#end
#interface flipsideviewcont:viewcont
{
sqlite *db;
}
#property()id<flipsideviewcontrollerdelegate>delegate;
#property()nsmutablearray *entries;
-(void)opendb;
-(nsstring*)filepath;
}
======================
#interface mainviewcontroller:viewcontroller<flipsideviewcontrollerdelegate>
{sqlite3 *db;}
#property()iboutlet nstextfiled *systext,*diatext,*commenttxt;
#property(readpnly,non)nsdate *currentdate;
-(void)createTable:(nsstring*)tablename
withfield1:(nsstring*)field1 withfield2:(nsstring*)field2 withfield3:(nsstring*)field3 withfield4:(nsstring*)field4;
-(ibaction)saveentry;
#implement mainview
-(void)createTable:(nsstring*)tablename
withfield1:(nsstring*)field1 withfield2:(nsstring*)field2 withfield3:(nsstring*)field3 withfield4:(nsstring*)field4
{
char *err;
nastring *sql=[nsstring stringwithformat:#"crete table if nat exist '%#'('%#'""text primary key,'%#' int,'%#' int,'%#'text);",tablename,field1,field2,field3,field4);
if(sqlite_exe(db,[sql utf*string],null,null,&err)!=sqlite_ok)
{sqlite_close(db);
}}
-(void)opendb;
{}
-(nsstring*)filepath()
-(void)viewdidload
{[self opendb];
[self createtable:#"summery" withfield:#"thedate withfield2:#"systonic"];}
-(ibaction)saveenrty
{
int sys=[systext.text intvalue];
int dia=[diatext.text intvalue];
nsstring *comm=comtext.tex;
nsdate *thedate=[nsdate date];
nsstring *sql=[nsstring stringwithformat:#"insert into summery('sys','thedate','dia',''com')values('%#','%d','%d','%#')",thedate,sys,dia,comm];
{sqlite_close(db);
}
systext.text="";
didtext.text="";
commtext.text="";
}
}
-(void)prepareforsegue
{if([[segue identifier]isequalto string:#"showwale");
{[[segue destinationviewcont]setdelegate:self];
}
}
-(void)flipsideviewcontdidfinish
{[self dismissviewcontroller:yes];
}
}
}