BLOB data is not displaying in UITextView - iphone

hello,
I am stucked at the last part of it, Please help me on it.
In this there are three views, first one, for list of books( in UITableView), second is chapters(in UITableView) and last one is for content,which is in text format (in UITextView).
Upto second view it is working very fine.Problem is, when i select any chapters in second view, text view in third view displays nothing.But in output it displays the sequence of numbers.
code to fetch data from database and display into UITextView.
NSMutableString *mStr = [NSMutableString stringWithFormat:#"select content from content where name = \"%#\" and chapterno = %#",chapName,chapNo];
const char *sql =(char *)[mStr UTF8String];
sqlite3_stmt *sqlStmt;
if(sqlite3_prepare(dbContent, sql, -1, &sqlStmt, NULL)!=SQLITE_OK)
{
NSLog(#"prob with prepare statement: %s",sqlite3_errmsg(dbContent));
}
else
{
while (sqlite3_step(sqlStmt)==SQLITE_ROW) {
len = sqlite3_column_bytes(sqlStmt, 0);
NSData *cData = [[NSData alloc]initWithBytes:sqlite3_column_blob(sqlStmt, 0) length:len];
NSString *nstr = [NSString stringWithUTF8String:[cData bytes]];
myTextView.text = nstr;
}
In above chapName is coming from first view and chapNo is selected row in second view.
content table looks like:
id bookid name chapterno content
1 1 abc 1 BLOB(size:4217)
2 1 abc 2 BLOB(size:3193)
3 1 abc 3 BLOB(size:3501)
O/p comes in a long sequence of numbers like this..
<0d0a3120 496e2074 68652062 6567696e 6e696e67 20476f64 20637265 61746564 20746865 20686561 76656e20 616e6420 74686520 65617274 682e0d0a...>
Here, text content i need to display in text view. What i'm missing here?

I think the problem is NSData to NSString conversion. If your Sqlite strings are not null-terminated converting with following line should help.
NSString* nStr = [[NSString alloc] initWithData:cData
encoding:NSUTF8StringEncoding];

NSMutableArray *ar=[[NSMutableArray alloc] init];
NSString *strQuery=[NSString stringWithFormat:#"select content from content where name = \"%#\" and chapterno = %#",chapName,chapNo];
const char *sql =[mStr UTF8String];
sqlite3_stmt *sqlStmt;
if(sqlite3_open([self.dbPath UTF8String], &database)==SQLITE_OK)
{
if(sqlite3_prepare_v2(database, query, -1, &compiledStmt, NULL)==SQLITE_OK){
while (sqlite3_step(sqlStmt)==SQLITE_ROW) {
len = sqlite3_column_bytes(sqlStmt, 0);
NSData *cData = [[NSData alloc]initWithBytes:sqlite3_column_blob(sqlStmt, 0) length:len];
NSString *nstr = [NSString stringWithUTF8String:[cData bytes]];
myTextView.text = nstr;
[ar addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:[NSData dataWithBytes:sqlite3_column_blob(compiledStmt, 1) length:sqlite3_column_bytes(compiledStmt, 1)],#"data1",
[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStmt, 2)],#"data2",nil]];
}
else {
NSLog(#"Invalid query");
}
NSArray *arToReturn=([ar count]>;0)?[NSArray arrayWithArray:ar]:nil;
ar=nil;
return arToReturn;
}
Please implement following code and let me inform any problem and query genrated.

I have found a simplest alternate way for it.
Since, I am taking book name(from first table view) and chapter number(from second table view) from the database and passing it to detail view page.
Lets say here, my books names are maths, physics, geography..and chapters are in numerals (1,2,3...).Only thing is needed to keep the file name as
[booknamechpatername.txt]
#book name- Maths
chapter1-->> maths1.txt
chapter2-->> maths2.txt
...
#book name - Physics
chapter1 -->> physics12.txt
...
geography21.txt
...so on..
and drag it to iphone resource or any folder you want.
Now, Store that file into string and display into UITextView.
-(void)loadFile{
NSError *error;
NSArray *dirPath = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *docDir = [dirPath objectAtIndex:0];
if (!docDir) {
NSLog(#"Doc dir not found");
}
NSString *str = [[NSBundle mainBundle]pathForResource:[NSString stringWithFormat:#"%#%#",chapName,chapNo] ofType:#"txt"];
NSString *content = [NSString stringWithContentsOfFile:str encoding:NSUTF8StringEncoding error:&error];
myTextView.text = content;
}
and call it in viewDidLoad
[self loadFile];
Otherwise, this link https://github.com/jblough/bible-ios would help, if you want to go through database only.

Related

How to get original special characters from SQLite db using iPhone SDK?

I am inserting HTML content (which has special characters like bullets, etc) into the SQLite database.
When I try to get the content on a view, it does not show the special characters correctly. It shows me junk text.
How can I ensure that whatever text I insert in database, it is displayed correctly on the view.
Thanks!
My Insertion code:
// This query method implementation is in different file
- (NSArray *)executeQuery:(NSString *)sql arguments:(NSArray *)args {
sqlite3_stmt *sqlStmt;
if (![self prepareSql:sql inStatament:(&sqlStmt)])
return nil;
int i = 0;
int queryParamCount = sqlite3_bind_parameter_count(sqlStmt);
while (i++ < queryParamCount)
[self bindObject:[args objectAtIndex:(i - 1)] toColumn:i inStatament:sqlStmt];
NSMutableArray *arrayList = [[NSMutableArray alloc] init]; // By Devang
int columnCount = sqlite3_column_count(sqlStmt);
while ([self hasData:sqlStmt]) {
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
for (i = 0; i < columnCount; ++i) {
id columnName = [self columnName:sqlStmt columnIndex:i];
id columnData = [self columnData:sqlStmt columnIndex:i];
[dictionary setObject:columnData forKey:columnName];
}
[arrayList addObject:dictionary];
//[arrayList addObject:[dictionary autorelease]];
}
sqlite3_finalize(sqlStmt);
return arrayList;
}
// now call this method by make object for this file
NSString *inserQuery =[NSString stringWithFormat:#"insert into feedtest (title,summary,image,id) values ('%#','%#','%#',%d)",cell.textLabel.text,source,returnURL,indexPath.row];
NSLog(#"query - %#",inserQuery);
[database executeQuery:inserQuery];
// Retrive the data
NSString *sd=[NSString stringWithFormat:#"Select title,summary from feedtest"];
NSMutableArray *p=[[NSMutableArray alloc]init];
p=[[database executeQuery:sd ] mutableCopy];
[database close];
NSString *titleHTML = [[p objectAtIndex:i]valueForKey:#"title"];
NSString *postHTML =[[p objectAtIndex:i]valueForKey:#"summary"];
NSLog(#"%#",titleHTML);
NSLog(#"%#",postHTML);
You can check your local database using FireFox plugin SQLite. But, sometimes on retrieving we faced strange problem like what is present in the storage not coming properly and sometime, there is crash. So my suggestion is what you should check encoding scheme(normally, it's not matter more) and while getting data use this:
[NSString stringWithFormat:#"%s",(const char*)sqlite3_column_text(statement, 4)] ;
instead of:
[NSString stringWithUTF8String:(const char*)sqlite3_column_text(statement, 4)];
Hope, this is what you're looking for. Any concern get back to me. :)

Convert captured image in to a separate png file, and insert that png file name as a string in to sqlite data base and retrieve it

In my iPhone app I need to capture a picture and save it in to the sqlite database.
NSString *insertQuery = [NSString stringWithFormat:#"INSERT INTO ProfileTable (NAME, MOBILE, EMAIL, ProfilePICTURE) VALUES(?, ?, ?, ?)"];
const char *insert = [insertQuery UTF8String];
if(sqlite3_prepare_v2(contactsDB, insert, -1, &insertStatement, NULL) != SQLITE_OK) {
NSLog(#"Error while creating insert Statement");
}
else
{
sqlite3_bind_text(insertStatement, 1, [name UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(insertStatement, 2, [mobile UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(insertStatement, 2, [email UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_blob(insertStatement, 4, [profilePic bytes], [contactImage length], NULL);
}
}
// Same Query for insert statement also
I saved that file in the form of blob type but that cause to occupy huge memory and causes to memory warnings.
So i have an idea that.
I want to save the captured image as a png file for suppose "image1.png" and insert that title "image1.png" as a varchar type and the retrieve that file having that name when we want to display.
any help how to do this
Get the document directory (or other directory that you might want to store the images):
/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
Store image as png:
NSURL *documentsDirURL = [self applicationDocumentsDirectory];
NSURL *fileURL = [documentsDirURL URLByAppendingPathComponent:#"some-image-name.png"];
NSData* data = UIImagePNGRepresentation(image);
[data writeToURL:fileURL atomically:YES];
NSString *filePath = [fileURL path];
// now save your filePath as string to sqlite
Note, you'll have to fill in details, such as where the appropriate directory is in the filesystem, a naming convention, generating filenames unless they exist already etc.
EDIT:
Here's some help with serial naming of the images. There are a lot of different solutions.
Create an entry in the NSUserDefaults with the key #"lastImageNumber". When you need a new image name:
NSInteger imageNumber = [[NSUserDefaults standardUserDefaults] integerForKey:#"lastImageNumber"] + 1;
NSString *imageName = [NSString stringWithFormat:#"image%05d.png",imageNumber];
// save the new imageNumber in the `NSUserDefaults`
[[NSUserDefaults standardUserDefaults] setInteger:imageNum ForKey:#"lastImageNumber"];
Add int counter in appDelegate.h file
Also add In application didFinishLaunchingWithOptions method:
counter = 0;
if(![[NSUserDefaults standardUserDefaults] integerForKey:#"ImageNumber"])
{
[[NSUserDefaults standardUserDefaults] setInteger:counter ForKey:#"ImageNumber"]
}
else
{
counter = [[NSUserDefaults standardUserDefaults] integerForKey:#"ImageNumber"];
}
Also add this method in appDelegate.h file
+ (NSString *) applicationDocumentsDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
Now when ever adding captured image in database firstly add int Doc Directory like this:
appDelegate = (appDelegate *)[[UIApplication sharedApplication] delegate];
NSString *strDocDirPath = [appDelegate applicationDocumentsDirectory];
NSString *fileName = [NSString stringWithFormat:#"Image%03d.png",appDelegate.counter];
strDocDirPath = [strDocDirPath stringByAppendingPathComponent:fileName];
NSData* imgdata = UIImagePNGRepresentation(yourCapturedImage);
[imgdata writeToFile:strDocDirPath atomically:YES];
appDelegate.counter ++;
[[NSUserDefaults standardUserDefaults] setInteger:appDelegate.counter ForKey:#"ImageNumber"];
//add in database with fileName
Retrieve like this:
appDelegate = (appDelegate *)[[UIApplication sharedApplication] delegate];
NSString *strDocDirPath = [appDelegate applicationDocumentsDirectory];
strDocDirPath = [strDocDirPath stringByAppendingPathComponent:#"Image001.png"]; //use your database image name here
UIImage *img = [[UIImage alloc]initWithContentsOfFile:strDocDirPath];
Every time you can Create a Random String and Rename that image Which you capture to Randomly generated string.
NSString *letters = #"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
NSMutableString *randomString = [NSMutableString stringWithCapacity:6];
for (int i=0; i<6; i++)
{
[randomString appendFormat: #"%C", [letters characterAtIndex: arc4random() % [letters length]]];
}
NSString *fileName = [NSString stringWithFormat:#"%#.png",randomString];
Hope this will Help.

When I use the TFHpple parser HTML on iPhone , and already find the node ,but the content return is NULL?

the Code:
NSString *linkStr=#"http://www.voanews.com/content/obama_pledges_aid_to_drought_stricken_farmers/1484380.html";
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:linkStr]];
// Create parser
TFHpple *xpathParser = [[TFHpple alloc] initWithHTMLData:data];
//Get all the cells of the 2nd row of the 3rd table
NSArray *elements = [xpathParser searchWithXPathQuery:#"//p[#class='article_date']"];
// Access the first cell
if ([elements count] > 0)
{
TFHppleElement *element = [elements objectAtIndex:0];
// Get the text within the cell tag
NSString *content = [element content];
NSLog(#"VOA = %#",content); //Result : print NULL
}
[xpathParser release];
[data release];
but I use the XPath Helper query the "//p[#class='article_date']" ,it's ok, but in my code the content is null
Running your code example, if I change [element content] for [element text], my output is:
VOA = August 11, 2012
In its Github repo, they mention (at USAGE section):
[e text]; // The text inside the HTML element (the content of the
first text node)
And looking at the source code of the CONTENT method it uses objectForKey, where TFHppleContentKey = "nodeContent". See:
static NSString * const TFHppleNodeContentKey = #"nodeContent"
// Returns this tag's innerHTML content.
- (NSString *) content
{
return [node objectForKey:TFHppleNodeContentKey];
}
It seems that it's safe to use [element text] instead of [element content] in your example.
I hope it helps.

How to append an array on textfield in iphone

I have an application in which I want to fetch content from a database using a particular ID column and later display all that content in textfields on a button press. The snippet below shows how I fetch the content in an array.
//this is a function which i am created which will be called in button click event
-(NSArray*)getStudents
{
NSMutableArray *studentArray=[[NSMutableArray alloc]init];
sqlite3_stmt *statement = nil;
NSString *query=#"select * from UserInformation where UserId=?";
const char *sql = [query cStringUsingEncoding:NSUTF8StringEncoding];
if (sqlite3_prepare_v2(dbConnection, sql, -1, &statement, NULL) == SQLITE_OK) {
while(sqlite3_step(statement) == SQLITE_ROW) {
Student *newStudent=[[Student alloc]init];
newStudent.age=sqlite3_column_int(statement, 0);
newStudent.name=[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
[studentArray addObject:newStudent];
}
}
return studentArray;
}
I have a problem adding this array to my textfields so that when I click on the button my textfields are loaded with the values from the database for a particular userid. I have written the above function in one of my controllers and my textfields are defined in another controller. How do I fill the above array in my textfields?
USe below as reference code ..
//Get all your student object from database
NSArray* myArray = [self getStudents ];
//Use mutable string to append all the data in single string.
NSMutableString* stringName = [NSMutableString stringWithString:#""];
//Traverse through the Student array
for(id arrayObj in myArray)
{
Student* student = (Student*)arrayObj;
[stringName appendString:student.name];
[stringName appendString:#" ";
}
//Now you have stringName variable holding all the student name and this is space separated string
myTextField.text = stringName;

obj-c problem setting array with componentsSeperatedByString

I have a data source with about 2000 lines that look like the following:
6712,Anaktuvuk Pass Airport,Anaktuvuk Pass,United States,AKP,PAKP,68.1336,-151.743,2103,-9,A
What I am interested in is the 6th section of this string so I want to turn it into an array, then i want to check the 6th section [5] for an occurrance of that string "PAKP"
Code:
NSBundle *bundle = [NSBundle mainBundle];
NSString *airportsPath = [bundle pathForResource:#"airports" ofType:#"dat"];
NSData *data = [NSData dataWithContentsOfFile:airportsPath];
NSString *dataString = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
NSArray *dataArray = [dataString componentsSeparatedByString:#"\n"];
NSRange locationOfAirport;
NSString *workingString = [[NSString alloc]initWithFormat:#""];
NSString *searchedAirport = [[NSString alloc]initWithFormat:#""];
NSString *airportData = [[NSString alloc]initWithFormat:#""];
int d;
for (d=0; d < [dataArray count]; d=d+1) {
workingString = [dataArray objectAtIndex:d];
testTextBox = workingString; //works correctly
NSArray *workingArray = [workingString componentsSeparatedByString:#","];
testTextBox2 = [workingArray objectAtIndex: 0]; //correctly displays the first section "6712"
testTextBox3 = [workingArray objectAtIndex:1] //throws exception index beyond bounds
locationOfAirport = [[workingArray objectAtIndex:5] rangeOfString:#"PAKP"];
}
the problem is that when the workingArray populates, it only populates with a single object (the first component of the string which is "6712". If i have it display the workingString, it correctly displays the entire string, but for some reason, it isn't correctly making the array using the commas.
i tried it without using the data file and it worked fine, so the problem comes from how I am importing the data.
ideas?
You code works. You should run it with the debugger to see what's happening. At a guess, your input data isn't what you think it is - possibly a different encoding, or different line endings.
See sample:
NSString *dataString = #"6712,Anaktuvuk Pass Airport,Anaktuvuk Pass,United States,AKP,PAKP,68.1336,-151.743,2103,-9,A";
NSArray *dataArray = [dataString componentsSeparatedByString:#"\n"];
for (NSString *workingString in dataArray) {
NSString *testTextBox = workingString; //works correctly
NSArray *workingArray = [workingString componentsSeparatedByString:#","];
NSString *testTextBox2 = [workingArray objectAtIndex: 0]; //correctly displays the first section "6712"
NSString *testTextBox3 = [workingArray objectAtIndex:1]; //throws exception index beyond bounds
NSRange locationOfAirport = [[workingArray objectAtIndex:5] rangeOfString:#"PAKP"];
}
there was a problem in the data where there were a few "\"s that caused the errors.