Related
I have a problem with direction of messages in JSQMessage.
When I write and send message all good with direction but when I restart app or else that some messages changes its direction.
Its my code
#import "ChatViewController.h"
#import <AVKit/AVKit.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import "JSQMessagesCollectionViewFlowLayout.h"
#import "JSQMessages.h"
#import "JSQPhotoMediaItem.h"
#import "JSQLocationMediaItem.h"
#import "JSQVideoMediaItem.h"
#import "JSQMessagesMediaViewBubbleImageMasker.h"
#import "JSQMessagesAvatarImage.h"
#import "JSQMessagesAvatarImageFactory.h"
#import <JSQMessagesBubbleImage.h>
#import <JSQMessagesBubbleImageFactory.h>
#import <FirebaseDatabase/FirebaseDatabase.h>
#import <FirebaseStorage/FirebaseStorage.h>
#import <FirebaseAuth/FirebaseAuth.h>
#interface ChatViewController () <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
#property (strong, nonatomic) NSMutableArray *messages;
#property (strong, nonatomic) JSQMessagesBubbleImage *outgoingBubbleImageView;
#property (strong, nonatomic) JSQMessagesBubbleImage *incomingBubbleImageView;
#property (strong, nonatomic) FIRDatabaseReference *databaseReference;
#property (strong, nonatomic) NSString *convoId;
#end
#implementation ChatViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = self.senderDisplayName;
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"backgroundChat"]];
imageView.alpha = 0.5;
self.collectionView.backgroundView = imageView;
_messages = [NSMutableArray new];
_databaseReference = [[FIRDatabase database] reference];
[self setupBubbles];
self.collectionView.collectionViewLayout.incomingAvatarViewSize = CGSizeZero;
self.collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero;
NSString *receiverId = [_receiverData objectForKey:#"uId"];
NSString *receiverIdFive = [receiverId substringToIndex:5];
NSString *senderIdFive = [self.senderId substringToIndex:5];
if (senderIdFive > receiverIdFive) {
_convoId = [NSString stringWithFormat:#"%#%#", senderIdFive, receiverIdFive];
} else {
_convoId = [NSString stringWithFormat:#"%#%#", receiverIdFive, senderIdFive];
}
[self observeMessages];
}
- (IBAction)backButtonAction:(id)sender {
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UITabBarController *viewiewController = [mainStoryboard instantiateViewControllerWithIdentifier:#"HomeView"];
[self presentViewController:viewiewController animated:true completion:nil];
}
- (id<JSQMessageData>)collectionView:(JSQMessagesCollectionView *)collectionView messageDataForItemAtIndexPath:(NSIndexPath *)indexPath {
return _messages[indexPath.item];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return _messages.count;
}
- (void)setupBubbles {
JSQMessagesBubbleImageFactory *factory = [JSQMessagesBubbleImageFactory new];
_outgoingBubbleImageView = [factory outgoingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleBlueColor]];
_incomingBubbleImageView = [factory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]];
}
- (id<JSQMessageBubbleImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView messageBubbleImageDataForItemAtIndexPath:(NSIndexPath *)indexPath {
JSQMessage *message = _messages[indexPath.item];
if (message.senderId == self.senderId) {
return _outgoingBubbleImageView;
} else {
return _incomingBubbleImageView;
}
}
- (id<JSQMessageAvatarImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView avatarImageDataForItemAtIndexPath:(NSIndexPath *)indexPath {
return nil;
}
- (UICollectionViewCell *)collectionView:(JSQMessagesCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
JSQMessagesCollectionViewCell *cell = [super collectionView:collectionView cellForItemAtIndexPath:indexPath];
JSQMessage *message = _messages[indexPath.item];
if (message.senderId == self.senderId) {
cell.textView.textColor = [UIColor whiteColor];
} else {
cell.textView.textColor = [UIColor blackColor];
}
return cell;
}
- (void)collectionView:(JSQMessagesCollectionView *)collectionView didTapMessageBubbleAtIndexPath:(NSIndexPath *)indexPath {
JSQMessage *message = _messages[indexPath.row];
if (message.isMediaMessage) {
JSQVideoMediaItem *mediaItem = (JSQVideoMediaItem *)message.media;
if (mediaItem != nil) {
AVPlayer *player = [AVPlayer playerWithURL:mediaItem.fileURL];
AVPlayerViewController *playerViewController = [AVPlayerViewController new];
playerViewController.player = player;
[self presentViewController:playerViewController animated:true completion:nil];
}
}
}
- (void)didPressSendButton:(UIButton *)button withMessageText:(NSString *)text senderId:(NSString *)senderId senderDisplayName:(NSString *)senderDisplayName date:(NSDate *)date {
FIRDatabaseReference *itemReference = [[[_databaseReference child:#"message"] child:[NSString stringWithFormat:#"%#", _convoId]] childByAutoId];
NSDictionary *messageItem = #{#"text":text, #"senderId":senderId, #"mediaType":#"TEXT"};
[itemReference setValue:messageItem];
[JSQSystemSoundPlayer jsq_playMessageSentSound];
[self finishSendingMessageAnimated:YES];
}
- (void)didPressAccessoryButton:(UIButton *)sender {
UIAlertController *sheet = [UIAlertController alertControllerWithTitle:#"Send file" message:#"Appearance media files in messages depend of your internet speed" preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *image = [UIAlertAction actionWithTitle:#"Image Library" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self getMediaFrom:kUTTypeImage];
}];
UIAlertAction *video = [UIAlertAction actionWithTitle:#"Video Library" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self getMediaFrom:kUTTypeMovie];
}];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:nil];
[sheet addAction:image];
[sheet addAction:video];
[sheet addAction:cancel];
sheet.popoverPresentationController.sourceView = self.view;
sheet.popoverPresentationController.sourceRect = CGRectMake(CGRectGetMinX(self.view.frame), CGRectGetMaxY(self.view.frame), sheet.accessibilityFrame.size.width, sheet.accessibilityFrame.size.height);
[self presentViewController:sheet animated:true completion:nil];
}
- (void)getMediaFrom:(CFStringRef)type {
UIImagePickerController *picker = [UIImagePickerController new];
picker.delegate = self;
picker.mediaTypes = #[(__bridge NSString *)type];
[self presentViewController:picker animated:true completion:nil];
}
- (void)observeMessages {
FIRDatabaseQuery *messagesQuery = [[_databaseReference child:[NSString stringWithFormat:#"message/%#", _convoId]] queryLimitedToLast:25];
[messagesQuery observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
if (snapshot.value[#"senderId"] != nil) {
NSString *ID = snapshot.value[#"senderId"];
NSString *mediaType = snapshot.value[#"mediaType"];
if ([mediaType isEqual:#"TEXT"]) {
NSString *text = snapshot.value[#"text"];
[_messages addObject:[JSQMessage messageWithSenderId:ID displayName:#"" text:text]];
} else if ([mediaType isEqual:#"PHOTO"]) {
NSString *image = snapshot.value[#"fileUrl"];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:image]];
JSQPhotoMediaItem *photoItem = [[JSQPhotoMediaItem alloc] initWithImage:[UIImage imageWithData:data]];
[_messages addObject:[JSQMessage messageWithSenderId:ID displayName:#"" media:photoItem]];
} else if ([mediaType isEqual:#"VIDEO"]) {
NSString *video = snapshot.value[#"fileUrl"];
JSQVideoMediaItem *videoItem = [[JSQVideoMediaItem alloc] initWithFileURL:[NSURL URLWithString:video] isReadyToPlay:true];
[_messages addObject:[JSQMessage messageWithSenderId:ID displayName:#"" media:videoItem]];
}
[self finishReceivingMessage];
}
}];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
UIImage *image = info[UIImagePickerControllerOriginalImage];
NSURL *video = info[UIImagePickerControllerMediaURL];
if (image != nil) {
[self sendMedia:image and:nil];
} else if (video != nil) {
[self sendMedia:nil and:video];
}
[picker dismissViewControllerAnimated:true completion:nil];
[self.collectionView reloadData];
}
- (void)sendMedia:(UIImage *)image and:(NSURL *)video {
if (image != nil) {
NSString *filePath = [NSString stringWithFormat:#"%#/%f", [FIRAuth auth].currentUser, [NSDate date].timeIntervalSinceReferenceDate];
NSData *data = UIImageJPEGRepresentation(image, 0.3);
FIRStorageMetadata *metadata = [FIRStorageMetadata new];
metadata.contentType = #"image/jpg";
[[[[FIRStorage storage] reference] child:filePath] putData:data metadata:metadata completion:^(FIRStorageMetadata * _Nullable metadata, NSError * _Nullable error) {
if (error != nil) {
NSLog(#"%#", error.localizedDescription);
return;
}
NSString *fileURL = [metadata downloadURLs][0].absoluteString;
FIRDatabaseReference *newMessage = [[_databaseReference child:[NSString stringWithFormat:#"message/%#", _convoId]] childByAutoId];
NSDictionary *messageItem = #{#"fileUrl":fileURL, #"senderId":self.senderId, #"mediaType":#"PHOTO"};
[newMessage setValue:messageItem];
}];
} else if (video != nil) {
NSString *filePath = [NSString stringWithFormat:#"%#/%f", [FIRAuth auth].currentUser, [NSDate date].timeIntervalSinceReferenceDate];
NSData *data = [NSData dataWithContentsOfURL:video];
FIRStorageMetadata *metadata = [FIRStorageMetadata new];
metadata.contentType = #"video/mp4";
[[[[FIRStorage storage] reference] child:filePath] putData:data metadata:metadata completion:^(FIRStorageMetadata * _Nullable metadata, NSError * _Nullable error) {
if (error != nil) {
NSLog(#"%#", error.localizedDescription);
return;
}
NSString *fileURL = [metadata downloadURLs][0].absoluteString;
FIRDatabaseReference *newMessage = [[_databaseReference child:[NSString stringWithFormat:#"message/%#", _convoId]] childByAutoId];
NSDictionary *messageItem = #{#"fileUrl":fileURL, #"senderId":self.senderId, #"mediaType":#"VIDEO"};
[newMessage setValue:messageItem];
}];
}
}
#end
What wrong with my code?
I have a quiz.vc and i am passing an NSString from on vc to another and it passes null. (i am using a UITextView)
Quiz.h
#property (nonatomic,strong) IBOutlet UITextView *textField;
#property (nonatomic, retain) NSString *userText;
Quiz.m
- (IBAction)next:(id)sender {
// i have tried NSString *userText also and passing in userText to sfvc.string
self.userText = self.textField.text;
selectFriendsViewController *sfvc = [[selectFriendsViewController alloc] init];
sfvc.string = self.userText;
}
selectFriendsViewController.h
#property (nonatomic, strong) NSString *string;
selectFriendsViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%#", _string);
}
its always logging null at runtime? i have tried so many ways and methods!
any ideas as to how i can pass a string and not null???
Thanks
Your error
selectFriendsViewController *sfvc = [[selectFriendsViewController alloc] init];
sfvc.string = self.userText;
This create a new instance of selectFriendsViewController,but you do not use it.It will be dealloced when the method is done.So,you got nothing.
If you fire a segue in the IBAction,use prepareForSegue to pass data.
Edit,
If you fire a segue when the button clicked.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.destinationViewController isKindOfClass:[selectFriendsViewController class]]) {
selectFriendsViewController * dvc = (selectFriendsViewController*)segue.destinationViewController;
dvc.string = self.textField.text;
}
}
If you don't want to show null,use the below code
#pragma mark - check string is empty or not
- (IBAction)next:(id)sender
{
self.userText = self.textField.text;
selectFriendsViewController *sfvc = [[selectFriendsViewController alloc] init];
sfvc.string = [self checkEmpty:self.userText];
}
- (void)checkEmpty:(NSString *)check
{
#try
{
if (check.length==0)
check = #" ";
if([check isEqual:[NSNull null]])
check = #" ";
}
#catch (NSException *exception)
{
check = #" ";
}
}
I think u can't navigate and push the value to next viewController
use this code if you using xib files.
- (IBAction)next:(id)sender {
selectFriendsViewController *sfvc = [[selectFriendsViewController alloc] init];
sfvc.string = self.textField.text;
[self.navigationController pushViewController:sfvc animated:YES];
}
hope that code helps you.
In my iOS app, I'm displaying images inside multiple UITableViewCells. However, it's not displaying the correct images in each cell.
First I load some content from a Feedly stream with the method below:
- (void)loadStreams {
NSString *feedName = [NSString stringWithFormat:#"%#-id", self.category];
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *accessToken = [standardUserDefaults objectForKey:#"AccessToken"];
NSString *feedId = [standardUserDefaults objectForKey:feedName];
NSString *feedPartial = [feedId stringByReplacingOccurrencesOfString:#"/" withString:#"%2F"];
NSString *feedUrl = [NSString stringWithFormat:#"https://sandbox.feedly.com/v3/streams/%#/contents", feedPartial];
NSLog(#"The Feedly url is: %#", feedUrl);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:feedUrl]];
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[mutableRequest addValue:accessToken forHTTPHeaderField:#"Authorization"];
request = [mutableRequest copy];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *jsonArray = (NSArray *)[responseObject objectForKey:#"items"];
self.continuation = [responseObject objectForKey:#"continuation"];
NSMutableArray *tempStreams = [[NSMutableArray alloc] init];
for (NSDictionary *dic in jsonArray) {
NSLog(#"Dic contains: %#", dic);
NSDictionary *originArray = [dic objectForKey:#"origin"];
NSDictionary *visualArray = [dic objectForKey:#"visual"];
NSArray *alternateArray = [dic objectForKey:#"alternate"];
NSDictionary *alternate = [alternateArray objectAtIndex:0];
NSString *image = [visualArray objectForKey:#"url"];
NSString *title = [dic objectForKey:#"title"];
NSString *author = [dic objectForKey:#"author"];
NSString *date = [dic objectForKey:#"published"];
NSDictionary *contentum = [dic objectForKey:#"content"];
NSString *content = [contentum objectForKey:#"content"];
NSString *owner = [originArray objectForKey:#"title"];
NSString *givenid = [dic objectForKey:#"id"];
NSString *href = [alternate objectForKey:#"href"];
NSDate *publisher = [NSDate dateWithTimeIntervalSince1970:([date doubleValue] / 1000.0)];
NSString *published = publisher.timeAgoSinceNow;
NSDictionary *data = [[NSDictionary alloc] initWithObjectsAndKeys:title, #"title", image, #"imageurl", published, #"published", owner, #"owner", content, #"content", givenid, #"givenid", href, #"href", author, #"author", nil];
Stream *stream = [[Stream alloc] initWithDictionary:data];
[tempStreams addObject:stream];
}
self.streams = [[NSMutableArray alloc] initWithArray:tempStreams];
tempStreams = nil;
[self.tableView reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Services"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
}];
[operation start];
}
This passes the data to an object called Stream, which consists of the code below:
Stream.h
#import <Foundation/Foundation.h>
#interface Stream : NSObject
#property (strong, nonatomic)NSString *name;
#property (strong, nonatomic)NSString *thumbnail;
#property (strong, nonatomic)NSString *photo;
#property (strong, nonatomic)NSString *published;
#property (strong, nonatomic)NSString *content;
#property (strong, nonatomic)NSString *givenid;
#property (strong, nonatomic)NSString *linky;
#property (strong, nonatomic)NSString *author;
- (id)initWithName:(NSString *)aName
thumbnail:(NSString *)aThumbnail
photo:(NSString *)aPhoto
published:(NSString *)aPublished
content:(NSString *)aContent
givenid:(NSString *)aId
linky:(NSString *)aLinky
author:(NSString *)aAuthor;
- (id)initWithDictionary:(NSDictionary *)dic;
#end
Stream.m
#import "Stream.h"
#implementation Stream
//The designed initializer
- (id)initWithName:(NSString *)aName
thumbnail:(NSString *)aThumbnail
photo:(NSString *)aPhoto
published:(NSString *)aPublished
content:(NSString *)aContent
givenid:(NSString *)aId
linky:(NSString *)aLinky
author:(NSString *)aAuthor{
self = [super init];
if (self) {
self.name = aName;
self.thumbnail = aThumbnail;
self.photo = aPhoto;
self.published = aPublished;
self.content = aContent;
self.givenid = aId;
self.linky = aLinky;
self.author = aAuthor;
}
return self;
}
- (id)initWithDictionary:(NSDictionary *)dic {
self = [self initWithName:dic[#"title"] thumbnail:dic[#"imageurl"] photo:dic[#"imageurl"] published:dic[#"published"] content:dic[#"content"] givenid:dic[#"givenid"] linky:dic[#"href"] author:dic[#"author"]];
return self;
}
- (id)init {
self = [self initWithName:#"Undifined" thumbnail:#"Undifined" photo:#"Undifined" published:#"Undifined" content:#"Undifined" givenid:#"Undifined" linky:#"Undifined" author:#"Undifined"];
return self;
}
#end
And in the end I build a cell like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * reuseIdentifier = #"programmaticCell";
MGSwipeTableCell * cell = [self.tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (!cell) {
cell = [[MGSwipeTableCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
}
CGFloat brightness = [UIScreen mainScreen].brightness;
cell.textLabel.text = [self.streams[indexPath.row] name];
cell.detailTextLabel.text = [self.streams[indexPath.row] published];
NSString *imageUrl = [NSString stringWithFormat: #"%#", [self.streams[indexPath.row] photo]];
NSLog(#"Image is: %# and path is: %d", imageUrl, indexPath.row);
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:imageUrl]
placeholderImage:[UIImage imageNamed:#"tile-blue.png"] options:indexPath.row == 0 ? SDWebImageRefreshCached : 0];
cell.delegate = self; //optional
return cell;
}
What happens though, is that it displays the wrong image in a lot of cells and sometimes the same image for a couple of cells. What am I doing wrong here?
These are symptoms of cell reuse. There are two issues you will have to deal with.
(1) you should reset your cell's content before it is reused. To do this you can override prepareForReuse in the cell and nil out the relevant properties (such as cell.imageView). If you don't do this, you will see the old image -after- the cell has been recycled, before SDWebImage has assigned a new image.
(2) as SDWebImage image retrieval is async, the image may arrive after the cell has scrolled off the screen (and recycled with new content. You need to check whether the image is still relevant before assigning it to the imageView. I am not sure if this is possible with the SDWebImage UIImageView category method. You may have to dissect SDWebImage a little . You can get more control over the process using the SDWebImageManager method:
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
options:(SDWebImageOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;
You could use it something like this (in CellForRowAtIndexPath)
[[SDWebImageManager defaultManager] downloadImageWithURL:url
options:0
progress:nil
completed:
^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if ([[tableView indexPathForCell:cell] isEqual:indexPath]) {
//image is still valid for this cell
cell.image = image;
}
}];
Push a unique id on the stack before your closure and check it when your closure completes
prepareForReuse
Like this:
func updateArtistImage(url: URL) {
let _eventId = self.event?.id
SDWebImageManager.shared().loadImage(with: url, options: [], progress: nil) { (image, data, error, cacheType, finished, url) in
if self.event!.id == _eventId {
if error == nil {
self.artistImageView.image = image
} else {
self.artistImageView.image = UIImage(named: "error_image")
}
}
}
}
and this:
override func prepareForReuse() {
super.prepareForReuse()
self.artistImageView.image = nil
}
So I currently have a functioning way of saving settings for my Cocos2d game, and the method I am using is an XML parser.
First of all, is it better to use NSUserDefaults for something like this?
EDIT: I DO APPOLOGIZE FOR THE LONG POST, IF YOU ALREADY KNOW HOW AN XML PARSER WORKS JUST SKIP TO THE END.
Here is my GlobalSettings.h:
#import <Foundation/Foundation.h>
#interface GlobalSettings : NSObject {
// Declare variables with an underscore in front, for example:
int _currency;
BOOL _BankerBossDefeated;
BOOL _BabyBossDefeated;
BOOL _DuckBossDefeated;
BOOL _BaseBallBossDefeated;
BOOL _NewtonBossDefeated;
BOOL _CatchExtender;
BOOL _CatchExtenderEnabled;
BOOL _SpeedBoost;
BOOL _SpeedBoostEnabled;
}
// Declare your variable properties without an underscore, for example:
#property (nonatomic, assign) int currency;
#property (nonatomic, assign) BOOL BankerBossDefeated;
#property (nonatomic, assign) BOOL BabyBossDefeated;
#property (nonatomic, assign) BOOL DuckBossDefeated;
#property (nonatomic, assign) BOOL BaseBallBossDefeated;
#property (nonatomic, assign) BOOL NewtonBossDefeated;
#property (nonatomic, assign) BOOL SpeedBoost;
#property (nonatomic, assign) BOOL CatchExtender;
#property (nonatomic, assign) BOOL SpeedBoostEnabled;
#property (nonatomic, assign) BOOL CatchExtenderEnabled;
// Put your custom init method interface here:
-(id)initWithcurrency:(int)currency
BankerBossDefeated:(BOOL)BankerBossDefeated
BabyBossDefeated:(BOOL)BabyBossDefeated
DuckBossDefeated:(BOOL)DuckBossDefeated
BaseBallBossDefeated:(BOOL)BaseBallBossDefeated
NewtonBossDefeated:(BOOL)NewtonBossDefeated
CatchExtender:(BOOL)CatchExtender
SpeedBoost:(BOOL)SpeedBoost
CatchExtenderEnabled:(BOOL)CatchExtenderEnabled
SpeedBoostEnabled:(BOOL)SpeedBoostEnabled;
#end
My GlobalSettings.m is:
#import "GlobalSettings.h"
#implementation GlobalSettings
// Synthesize your variables here, for example:
#synthesize currency = _currency;
#synthesize BankerBossDefeated = _BankerBossDefeated;
#synthesize BabyBossDefeated = _BabyBossDefeated;
#synthesize DuckBossDefeated = _DuckBossDefeated;
#synthesize BaseBallBossDefeated = _BaseBallBossDefeated;
#synthesize NewtonBossDefeated = _NewtonBossDefeated;
#synthesize SpeedBoost = _SpeedBoost;
#synthesize CatchExtender = _CatchExtender;
#synthesize SpeedBoostEnabled = _SpeedBoostEnabled;
#synthesize CatchExtenderEnabled = _CatchExtenderEnabled;
// put your custom init method here which takes a variable
// for each class instance variable
-(id)initWithcurrency:(int)currency
BankerBossDefeated:(BOOL)BankerBossDefeated
BabyBossDefeated:(BOOL)BabyBossDefeated
DuckBossDefeated:(BOOL)DuckBossDefeated
BaseBallBossDefeated:(BOOL)BaseBallBossDefeated
NewtonBossDefeated:(BOOL)NewtonBossDefeated
CatchExtender:(BOOL)CatchExtender
SpeedBoost:(BOOL)SpeedBoost
CatchExtenderEnabled:(BOOL)CatchExtenderEnabled
SpeedBoostEnabled:(BOOL)SpeedBoostEnabled;{
if ((self = [super init])) {
// Set class instance variables based on values
// given to this method
self.currency = currency;
self.BankerBossDefeated = BankerBossDefeated;
self.BabyBossDefeated = BabyBossDefeated;
self.DuckBossDefeated = DuckBossDefeated;
self.BaseBallBossDefeated = BaseBallBossDefeated;
self.NewtonBossDefeated = NewtonBossDefeated;
self.CatchExtender = CatchExtender;
self.SpeedBoost = SpeedBoost;
self.CatchExtenderEnabled = CatchExtenderEnabled;
self.SpeedBoostEnabled = SpeedBoostEnabled;
}
return self;
}
- (void) dealloc {
[super dealloc];
}
#end
I then parse the XML with SettingsParser.h:
#import <Foundation/Foundation.h>
#class GlobalSettings;
#interface SettingsParser : NSObject {}
+ (GlobalSettings *)loadData;
+ (void)saveData:(GlobalSettings *)saveData;
#end
and SettingsParser.m:
#import "SettingsParser.h"
#import "GlobalSettings.h"
#import "GDataXMLNode.h"
#implementation SettingsParser
+ (NSString *)dataFilePath:(BOOL)forSave {
NSString *xmlFileName = #"GlobalSettings";
/***************************************************************************
This method is used to set up the specified xml for reading/writing.
Specify the name of the XML file you want to work with above.
You don't have to worry about the rest of the code in this method.
***************************************************************************/
NSString *xmlFileNameWithExtension = [NSString stringWithFormat:#"%#.xml",xmlFileName];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *documentsPath = [documentsDirectory stringByAppendingPathComponent:xmlFileNameWithExtension];
if (forSave || [[NSFileManager defaultManager] fileExistsAtPath:documentsPath]) {
return documentsPath;
NSLog(#"%# opened for read/write",documentsPath);
} else {
NSLog(#"Created/copied in default %#",xmlFileNameWithExtension);
return [[NSBundle mainBundle] pathForResource:xmlFileName ofType:#"xml"];
}
}
+ (GlobalSettings *)loadData {
/***************************************************************************
This loadData method is used to load data from the xml file
specified in the dataFilePath method above.
MODIFY the list of variables below which will be used to create
and return an instance of TemplateData at the end of this method.
***************************************************************************/
int currency;
BOOL BankerBossDefeated;
BOOL BabyBossDefeated;
BOOL DuckBossDefeated;
BOOL BaseBallBossDefeated;
BOOL NewtonBossDefeated;
BOOL CatchExtender;
BOOL SpeedBoost;
BOOL CatchExtenderEnabled;
BOOL SpeedBoostEnabled;
// Create NSData instance from xml in filePath
NSString *filePath = [self dataFilePath:FALSE];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
if (doc == nil) { return nil; NSLog(#"xml file is empty!");}
NSLog(#"Loading %#", filePath);
/***************************************************************************
This next line will usually have the most customisation applied because
it will be a direct reflection of what you want out of the XML file.
***************************************************************************/
NSArray *dataArray = [doc nodesForXPath:#"//GlobalSettings" error:nil];
NSLog(#"Array Contents = %#", dataArray);
/***************************************************************************
We use dataArray to populate variables created at the start of this
method. For each variable you will need to:
1. Create an array based on the elements in the xml
2. Assign the variable a value based on data in elements in the xml
***************************************************************************/
for (GDataXMLElement *element in dataArray) {
NSArray *currencyArray = [element elementsForName:#"currency"];
NSArray *BankerBossDefeatedArray = [element elementsForName:#"BankerBossDefeated"];
NSArray *BabyBossDefeatedArray = [element elementsForName:#"BabyBossDefeated"];
NSArray *DuckBossDefeatedArray = [element elementsForName:#"DuckBossDefeated"];
NSArray *BaseBallBossDefeatedArray = [element elementsForName:#"BaseBallBossDefeated"];
NSArray *NewtonBossDefeatedArray = [element elementsForName:#"NewtonBossDefeated"];
NSArray *CatchExtenderArray = [element elementsForName:#"CatchExtender"];
NSArray *SpeedBoostArray = [element elementsForName:#"SpeedBoost"];
NSArray *CatchExtenderEnabledArray = [element elementsForName:#"CatchExtenderEnabled"];
NSArray *SpeedBoostEnabledArray = [element elementsForName:#"SpeedBoostEnabled"];
// currency
if (currencyArray.count > 0) {
GDataXMLElement *currencyElement = (GDataXMLElement *) [currencyArray objectAtIndex:0];
currency = [[currencyElement stringValue] intValue];
}
// BankerBossDefeated
if (BankerBossDefeatedArray.count > 0) {
GDataXMLElement *BankerBossDefeatedElement = (GDataXMLElement *) [BankerBossDefeatedArray objectAtIndex:0];
BankerBossDefeated = [[BankerBossDefeatedElement stringValue] boolValue];
}
// DuckBossDefeated
if (DuckBossDefeatedArray.count > 0) {
GDataXMLElement *DuckBossDefeatedElement = (GDataXMLElement *) [DuckBossDefeatedArray objectAtIndex:0];
DuckBossDefeated = [[DuckBossDefeatedElement stringValue] boolValue];
}
// BabyBossDefeated
if (BabyBossDefeatedArray.count > 0) {
GDataXMLElement *BabyBossDefeatedElement = (GDataXMLElement *) [BabyBossDefeatedArray objectAtIndex:0];
BabyBossDefeated = [[BabyBossDefeatedElement stringValue] boolValue];
}
// BaseBallBossDefeated
if (BaseBallBossDefeatedArray.count > 0) {
GDataXMLElement *BaseBallBossDefeatedElement = (GDataXMLElement *) [BaseBallBossDefeatedArray objectAtIndex:0];
BaseBallBossDefeated = [[BaseBallBossDefeatedElement stringValue] boolValue];
}
// NewtonBossDefeated
if (NewtonBossDefeatedArray.count > 0) {
GDataXMLElement *NewtonBossDefeatedElement = (GDataXMLElement *) [NewtonBossDefeatedArray objectAtIndex:0];
NewtonBossDefeated = [[NewtonBossDefeatedElement stringValue] boolValue];
}
// CatchExtender
if (CatchExtenderArray.count > 0) {
GDataXMLElement *CatchExtenderElement = (GDataXMLElement *) [CatchExtenderArray objectAtIndex:0];
CatchExtender = [[CatchExtenderElement stringValue] boolValue];
}
// SpeedBoost
if (SpeedBoostArray.count > 0) {
GDataXMLElement *SpeedBoostElement = (GDataXMLElement *) [SpeedBoostArray objectAtIndex:0];
SpeedBoost = [[SpeedBoostElement stringValue] boolValue];
}
// CatchExtenderEnabled
if (CatchExtenderEnabledArray.count > 0) {
GDataXMLElement *CatchExtenderEnabledElement = (GDataXMLElement *) [CatchExtenderEnabledArray objectAtIndex:0];
CatchExtenderEnabled = [[CatchExtenderEnabledElement stringValue] boolValue];
}
// SpeedBoost
if (SpeedBoostEnabledArray.count > 0) {
GDataXMLElement *SpeedBoostEnabledElement = (GDataXMLElement *) [SpeedBoostEnabledArray objectAtIndex:0];
SpeedBoostEnabled = [[SpeedBoostEnabledElement stringValue] boolValue];
}
}
/***************************************************************************
Now the variables are populated from xml data we create an instance of
TemplateData to pass back to whatever called this method.
The initWithExampleInt:exampleBool:exampleString will need to be replaced
with whatever method you have updaed in the TemplateData class.
***************************************************************************/
//NSLog(#"XML value read for exampleInt = %i", exampleInt);
//NSLog(#"XML value read for exampleBool = %i", exampleBool);
//NSLog(#"XML value read for exampleString = %#", exampleString);
GlobalSettings *Data = [[GlobalSettings alloc] initWithcurrency:currency
BankerBossDefeated:BankerBossDefeated
BabyBossDefeated:BabyBossDefeated DuckBossDefeated:DuckBossDefeated BaseBallBossDefeated:BaseBallBossDefeated NewtonBossDefeated:NewtonBossDefeated
CatchExtender:CatchExtender
SpeedBoost:SpeedBoost CatchExtenderEnabled:CatchExtenderEnabled
SpeedBoostEnabled:SpeedBoostEnabled];
[doc release];
[xmlData release];
return Data;
[Data release];
}
+ (void)saveData:(GlobalSettings *)saveData {
/***************************************************************************
This method writes data to the xml based on a TemplateData instance
You will have to be very aware of the intended xml contents and structure
as you will be wiping and re-writing the whole xml file.
We write an xml by creating elements and adding 'children' to them.
You'll need to write a line for each element to build the hierarchy // <-- MODIFY CODE ACCORDINGLY
***************************************************************************/
GDataXMLElement *GlobalSettingsElement = [GDataXMLNode elementWithName:#"GlobalSettings"];
GDataXMLElement *currencyElement = [GDataXMLNode elementWithName:#"currency"
stringValue:[[NSNumber numberWithInt:saveData.currency] stringValue]];
GDataXMLElement *BankerBossDefeatedElement = [GDataXMLNode elementWithName:#"BankerBossDefeated"
stringValue:[[NSNumber numberWithBool:saveData.BankerBossDefeated] stringValue]];
GDataXMLElement *BabyBossDefeatedElement = [GDataXMLNode elementWithName:#"BabyBossDefeated"
stringValue:[[NSNumber numberWithBool:saveData.BabyBossDefeated] stringValue]];
GDataXMLElement *DuckBossDefeatedElement = [GDataXMLNode elementWithName:#"DuckBossDefeated"
stringValue:[[NSNumber numberWithBool:saveData.DuckBossDefeated] stringValue]];
GDataXMLElement *BaseBallBossDefeatedElement = [GDataXMLNode elementWithName:#"BaseBallBossDefeated"
stringValue:[[NSNumber numberWithBool:saveData.BaseBallBossDefeated] stringValue]];
GDataXMLElement *NewtonBossDefeatedElement = [GDataXMLNode elementWithName:#"NewtonBossDefeated"
stringValue:[[NSNumber numberWithBool:saveData.NewtonBossDefeated] stringValue]];
GDataXMLElement *CatchExtenderElement = [GDataXMLNode elementWithName:#"CatchExtender"
stringValue:[[NSNumber numberWithBool:saveData.CatchExtender] stringValue]];
GDataXMLElement *SpeedBoostElement = [GDataXMLNode elementWithName:#"SpeedBoost"
stringValue:[[NSNumber numberWithBool:saveData.SpeedBoost] stringValue]];
GDataXMLElement *CatchExtenderEnabledElement = [GDataXMLNode elementWithName:#"CatchExtenderEnabled"
stringValue:[[NSNumber numberWithBool:saveData.CatchExtender] stringValue]];
GDataXMLElement *SpeedBoostEnabledElement = [GDataXMLNode elementWithName:#"SpeedBoostEnabled"
stringValue:[[NSNumber numberWithBool:saveData.SpeedBoost] stringValue]];
// Using the elements just created, set up the hierarchy
[GlobalSettingsElement addChild:currencyElement];
[GlobalSettingsElement addChild:BankerBossDefeatedElement];
[GlobalSettingsElement addChild:BabyBossDefeatedElement];
[GlobalSettingsElement addChild:DuckBossDefeatedElement];
[GlobalSettingsElement addChild:BaseBallBossDefeatedElement];
[GlobalSettingsElement addChild:NewtonBossDefeatedElement];
[GlobalSettingsElement addChild:CatchExtenderElement];
[GlobalSettingsElement addChild:SpeedBoostElement];
[GlobalSettingsElement addChild:CatchExtenderEnabledElement];
[GlobalSettingsElement addChild:SpeedBoostEnabledElement];
GDataXMLDocument *document = [[[GDataXMLDocument alloc]
initWithRootElement:GlobalSettingsElement] autorelease];
NSData *xmlData = document.XMLData;
NSString *filePath = [self dataFilePath:TRUE];
NSLog(#"Saving data to %#...", filePath);
[xmlData writeToFile:filePath atomically:YES];
}
#end
EDIT: THE ACTUAL PROBLEM BEGINS HERE:
In my menu class I have two switches that come up when CatchExtender and SpeedBoost become enabled (they are purchased in the game's store). In those switches, I want to set SpeedBoostEnabled and CatchExtenderEnabled depending on the switch.
These are the switches:
IN MY INIT:
if (GlobalSettings.CatchExtender == TRUE) {
if(GlobalSettings.SpeedBoost == TRUE){
catchSwitch = [[ UISwitch alloc ] initWithFrame: CGRectMake(220, 400, 10, 10)];
catchSwitch.center = CGPointMake(240, 450);
CCLabelTTF *catchLabel = [CCLabelTTF labelWithString:#"Catch Extender" fontName:#"Chalkduster" fontSize:15];
catchLabel.color = ccWHITE;
catchLabel.position = CGPointMake(240, 60);
[self addChild: catchLabel];
}else{
catchSwitch = [[ UISwitch alloc ] initWithFrame: CGRectMake(160, 400, 10, 10)];
catchSwitch.center = CGPointMake(160, 450);
CCLabelTTF *catchLabel = [CCLabelTTF labelWithString:#"Catch Extender" fontName:#"Chalkduster" fontSize:15];
catchLabel.color = ccWHITE;
catchLabel.position = CGPointMake(160, 60);
[self addChild: catchLabel];
}
catchSwitch.on = NO; //set to be OFF at start
catchSwitch.tag = 1; // this is not necessary - only to find later
[catchSwitch addTarget:self action:#selector(catchAction:) forControlEvents:UIControlEventValueChanged];
[[[CCDirector sharedDirector] openGLView] addSubview:catchSwitch];
}
if (GlobalSettings.SpeedBoost == TRUE) {
if(GlobalSettings.CatchExtender == TRUE){
speedSwitch = [[ UISwitch alloc ] initWithFrame: CGRectMake(100, 400, 10, 10)];
speedSwitch.center = CGPointMake(80, 450);
CCLabelTTF *speedLabel = [CCLabelTTF labelWithString:#"Speed Enhancer" fontName:#"Chalkduster" fontSize:15];
speedLabel.color = ccWHITE;
speedLabel.position = CGPointMake(80, 60);
[self addChild: speedLabel];
}else{
speedSwitch = [[ UISwitch alloc ] initWithFrame: CGRectMake(160, 400, 10, 10)];
speedSwitch.center = CGPointMake(160, 450);
}
speedSwitch.on = NO; //set to be OFF at start
speedSwitch.tag = 1; // this is not necessary - only to find later
[speedSwitch addTarget:self action:#selector(speedAction:) forControlEvents:UIControlEventValueChanged];
[[[CCDirector sharedDirector] openGLView] addSubview:speedSwitch];
}
IN THE ACTIONS:
- (void)catchAction:(id)sender
{
// Your logic when the switch it used
// NSLog(#"switchAction: value = %d", [sender isOn]);
if ([sender isOn]) {
GlobalSettings *GlobalSettings = [SettingsParser loadData];
GlobalSettings.CatchExtenderEnabled = TRUE;
UIAlertView* dialog = [[UIAlertView alloc] init];
[dialog setDelegate:self];
[dialog setTitle:#"ON"];
[dialog setMessage:#"Catch Extender is on"];
[dialog addButtonWithTitle:#"Sweet!"];
[dialog show];
[dialog release];
[SettingsParser saveData:GlobalSettings];
}else{
GlobalSettings *GlobalSettings = [SettingsParser loadData];
GlobalSettings.CatchExtenderEnabled = FALSE;
UIAlertView* dialog = [[UIAlertView alloc] init];
[dialog setDelegate:self];
[dialog setTitle:#"OFF"];
[dialog setMessage:#"Catch Extender is off"];
[dialog addButtonWithTitle:#"Thanks"];
[dialog show];
[dialog release];
[SettingsParser saveData:GlobalSettings];
}
}
- (void)speedAction:(id)sender
{
// Your logic when the switch it used
// NSLog(#"switchAction: value = %d", [sender isOn]);
if ([sender isOn]) {
GlobalSettings *GlobalSettings = [SettingsParser loadData];
GlobalSettings.SpeedBoostEnabled = TRUE;
UIAlertView* dialog = [[UIAlertView alloc] init];
[dialog setDelegate:self];
[dialog setTitle:#"ON"];
[dialog setMessage:#"Speed Enhancer is on"];
[dialog addButtonWithTitle:#"Sweet!"];
[dialog show];
[dialog release];
[SettingsParser saveData:GlobalSettings];
}else{
GlobalSettings *GlobalSettings = [SettingsParser loadData];
GlobalSettings.SpeedBoostEnabled = FALSE;
UIAlertView* dialog = [[UIAlertView alloc] init];
[dialog setDelegate:self];
[dialog setTitle:#"OFF"];
[dialog setMessage:#"Speed Enhancer is off"];
[dialog addButtonWithTitle:#"Thanks"];
[dialog show];
[dialog release];
[SettingsParser saveData:GlobalSettings];
}
}
In the classes that hold the data for the game levels, I check these Booleans normally with a simple if statement. But it doesn't seem to work, the settings don't seem to save because in the Log it doesn't seem like the values have changed in the XML file..
Again sorry for the long post but this issue is kinda bugging me.
I've never used Cocos2D before but this seems like exactly what you would use NSUserDefaults for in a typical iOS app, like this: [[NSUserDefaults standardUserDefaults] setBool:YES ForKey:#"Key"];
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];
}
}
}