Encoded nsstring becomes invalid, "normal" nsstring remains - iphone

I'm running into a problem with a string that contains encoded characters. Specifically, if the string has encoded characters it eventually becomes invalid while a "normal" string will not.
in the .h file:
#interface DirViewController : TTThumbsViewController
<UIActionSheetDelegate,UINavigationControllerDelegate,UIImagePickerControllerDelegate>
{
NSString *sourceFolder;
NSString *encodedSourceFolder;
}
#property (nonatomic, retain) NSString *sourceFolder;
#property (nonatomic, retain) NSString *encodedSourceFolder;
in the .m file:
- (id)initWithFolder:(NSString*)folder query:(NSDictionary*)query {
if (self = [super init]) {
sourceFolder = folder;
}
return self;
}
Up to now everything seems to run as expected. In viewDidLoad I have the following:
sourceFolderCopy = [self urlEncodeValue:(sourceFolder)];
//I also have this button, which I'll refer to later:
UIBarButtonItem *importButton = [[UIBarButtonItem alloc] initWithTitle:#"Import/Export" style:UIBarButtonItemStyleBordered
target:self
action:#selector(importFiles:)];
self.navigationItem.rightBarButtonItem = importButton;
Which uses the following method to encode the string (if it has characters I want encoded):
- (NSString *)urlEncodeValue:(NSString *)str {
NSString *result = (NSString *) CFURLCreateStringByAddingPercentEscapes (kCFAllocatorDefault, (CFStringRef)str, NULL, CFSTR(":/?#[]#!$&’()*+,;="), kCFStringEncodingUTF8);
return [result autorelease];
}
If I NSLog result, I get the expected values. If the string has characters like a white space, I get a string with encoding. If the string doesn't have any characters that need to be encoded, it just gives me the original string.
I have a button on the nav bar which begins an image import process by opening an action sheet. Once the method for the action sheet starts, my string is invalid - but only if it contains encoded characters. If it is just a "normal" string, everything is fine and acts as expected. Am I off on my encoding? At first I thought it might be a memory problem but I can't figure out why that would affect only encoded strings.
Here's where the action sheet is defined (and the first place I can see the encoded string becoming invalid) the NSLog statements are where it crashes:
- (IBAction)importFiles:(id)sender {
NSLog(#"logging encodedSF from import files:");
NSLog(#"%#",encodedSourceFolder);//crashes right here
NSLog(#"%#",sourceFolder);
if (shouldNavigate == NO)
{
NSString *msg = nil;
msg = #"It is not possible to import or export images while in image selection mode.";
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Unable to Import/Export"
message:msg
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
[msg release];
}
else{
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:#"What would you like to do?"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Import Photos (Picker)", #"Export Photos", nil, nil];
[actionSheet showInView:self.view];
[actionSheet release];
}
}
I don't get any crash errors going to the console. By using breakpoints I was able to see that the encodedSourceFolder is invalid in the action sheet method.

You should copy your passed in folder string in your initWithFolder:query: method like this or create a new string with:
- (id)initWithFolder:(NSString*)folder query:(NSDictionary*)query {
if (self = [super init]) {
sourceFolder = [folder copy];
}
return self;
}
Otherwise your string gets autoreleased elsewhere.

Do not use retain for NSString properties. Use copy:
#property (nonatomic, copy) NSString *sourceFolder;
There are several questions/answers here that explain this further, such as Chris Hanson's response at:
NSString property: copy or retain?

Related

German characters are not displaying properly

I am facing a problem on displaying characters :
Ex : My word is : Üniversäl
but it is displayed as : Üniversäl when I print this word.
How can I resolve this issue ?
As shown here It display proper word in hint :
but when I print the string str1 its printing Üniversäl
Problems with metal umlauts?
It depends on the encoding of the output channel you are using.
For example:
NSString *universal = #"Üniversäl";
NSLog(#"Üniversal: %#", universal);
printf("%s\n", [universal cStringUsingEncoding:NSMacOSRomanStringEncoding]);
printf("%s\n", [universal cStringUsingEncoding:NSISOLatin1StringEncoding]);
printf("%s\n", [universal cStringUsingEncoding:NSUTF8StringEncoding]);
"prints" the string to the terminal in three different encodings. Does one of them look right to you?
I would try changing your encoding to something more UTF8-ish
NSString *otherString = [[NSString alloc] initWithCString:"Üniversäl" encoding:NSMacOSRomanStringEncoding];
NSLog(#"%#",otherString); // outputs Üniversäl
NSString *string = [[NSString alloc] initWithCString:"Üniversäl" encoding:NSUTF8StringEncoding];
NSLog(#"%#",string); // outputs Üniversäl
This is not the answer but I wanted to add a screenshot to my comment.
I dragged and dropped a UILabel to my storyboard and attached it to label1. Every thing looks fine to me. I am using Xcode 4.6 with iOS 6. Tell me if I missed something?
#interface v1ViewController : UIViewController
#property (nonatomic, retain) IBOutlet UILabel *label1;
#end
#implementation v1ViewController
#synthesize label1;
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *tempArray = [[NSArray alloc] initWithObjects:#"Üniversäl", nil];
NSString *str2 = [tempArray objectAtIndex:0];
//NSLog(#"str2: %s",[str2 UTF8String]); // outputs Üniversäl
NSLog(#"str2: %#",str2); // outputs Üniversäl
label1.text = str2;
}

how to call a method within a method in iphone

i am facing problem when i call method within method of another class like this i have method for button when someone click on button
//within ViewController.m button method
-(IBAction)login:(id)sender
{
DBHelper *objdb = [[DBHelper alloc] init];
[objdb loginnow:textname.text andpassword:textpassword.text];
}
and this button method calling this method in DBhelper.m file and it succesfully calling this method
-(void) loginnow:(NSString *) username andpassword:(NSString *) password
{
[self createEditableCopyOfDatabaseIfNeeded];
[self initializeDatabase];
const char *sql;
NSString *querySQL = [NSString stringWithFormat: #"SELECT username, password FROM CONTACT WHERE username='%#' AND password='%#'",username,password];
sql = [querySQL UTF8String];
if (sqlite3_prepare_v2(database, sql, -1, &init_statement, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error: failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
}
while (sqlite3_step(init_statement) == SQLITE_ROW)
{
NSLog(#"char sql = %s" ,sql);
dbusername = [NSString stringWithUTF8String:(char *)sqlite3_column_text(init_statement,0)];
dbpassword = [NSString stringWithUTF8String:(char *)sqlite3_column_text(init_statement,1)];
}
if ([dbusername isEqualToString:username] && [dbpassword isEqualToString:password])
{
//DBHelper.callingViewController = self;
[self.callingViewController addview];
}
else if (dbusername != username || dbpassword != password)
{
NSLog(#"dbusername is = %#" ,dbusername);
NSLog(#"dbpassword is = %#" ,dbpassword);
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Login Failed"
message:#"Username Or Password is not Correct"
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:#"OK ", nil];
[alert show];
[alert release];
}
sqlite3_reset(init_statement);
[self closeDatabase];
}
and also in DBhelper.h i define property for this
#property (strong) ViewController * callingViewController;
and within if condidtion in lognow method if password and username is succesully match i am calling this mathod in Viewcontroller.com file but am fail to call that
//ViewController.m
-(void) addview
{
DBHelper *f = [[DBHelper alloc] init];
f.callingViewController = self;
newview.center = CGPointMake(1000, 1000);
}
Though it's not wise to hold the viewController in the DBhelper(it breaks MVC), you could call your ViewController's method as your code but remember to set to pass your ViewController to the DBhelper. Maybe like this:
//ViewController.m
-(IBAction)login:(id)sender
{
DBHelper *objdb = [[DBHelper alloc] init];
[objdb loginnow:textname.text andpassword:textpassword.text viewController:self];
}
//DBHelper.m
-(void) loginnow:(NSString *) username andpassword:(NSString *)password viewController:(ViewController *)vc
{ ...
if ([dbusername isEqualToString:username] && [dbpassword isEqualToString:password])
{
[vc addview];
}
...
}
But in fact you should use a delegate (or block or notification, but delegate is the most case) here. Like this:
In DBHelper.h, before #interface, add
#class DBHelper;
#protocol DBHelperDelegate <NSObject>
-(void) DBHelp:(DBHelper *)helper didFinishedLoginSuc:(BOOL)suc;
#end
and between the #interface and #end tag, add(suppose you are not using ARC)
#property (nonatomic, assign) id delegate;
in the DBHelper.m, in the #implementation, add(suppose you are not using auto synthesize)
#synthesize delegate = _delegate;
Now, you can change the [self.callingViewController addview]; to
if (self.delegate && [self.delegate responseToSelector:#selector(DBHelp:didFinishedLoginSuc:)]) {
[self.delegate DBHelp:self didFinishedLoginSuc:YES];
}
Now you get a delegate prepared for every view controller which obey the DBHelperDelegate.
In your ViewController.h, tell the compiler that it obey the DBHelperDelegate by add behind the class declare:
#interface ViewController:UIViewController<DBHelperDelegate>
and change the addView method name to
-(void) DBHelp:(DBHelper *)helper didFinishedLoginSuc:(BOOL)suc
At last, when you click the button, set self as the objdb's delegate
-(IBAction)login:(id)sender
{
DBHelper *objdb = [[DBHelper alloc] init];
objdb.delegate = self;
[objdb loginnow:textname.text andpassword:textpassword.text];
}
Now, when you login successfully, -(void) DBHelp:(DBHelper *)helper didFinishedLoginSuc:(BOOL)suc in ViewController.m will be called and you can deal with your view.
Remember to set the delegate to nil when your viewController gets dealloc, or you will expect an memory error. Be careful.

Iphone variable is loading syntax it seems and not the variable

I'm assigning a variable string from an XML node and for some reason when i'm using it later i'm getting it read like this:
edit
The Current URL to parse is a NSLog that is written when the page is loaded from the [loadXML currentCat]]
NSLog:
Current URL To Parse: <UILongPressGestureRecognizer: 0x677c240; state = Possible; view = <UITableViewCellContentView 0x67780b0>; target= <(action=_longPressGestureRecognized:, target=<UITableViewCell 0x677c340>)
tempFullUrl being set - this is in my class.h
#interface PromotionViewController : UITableViewController {
NSString *tempFullUrl;
}
#property (nonatomic, retain) NSString *tempFullUrl;
#end
It's also synthasised in the .m
Var being Set:
NSArray *urlArray = [item elementsForName:kName_url];
for(CXMLElement *url in urlArray)
{
newobj.urlSearch = url.stringValue;
tempFullUrl = url.stringValue;
NSLog(#"Temp Full URL: : %#", tempFullUrl);
[url release];
[kName_url release];
}
[totalArray addObject:newobj];
}}
Var being used:
else if(currentType == #"p2FullSearch") {
NSString *searchType = #"categorySearch";
PromotionViewController *loadXML = [[PromotionViewController alloc] initWithNibName:#"PromotionViewController" bundle:nil];
[loadXML setCurrentCat: tempFullUrl];
[loadXML setCurrentType: searchType];
[self.navigationController pushViewController:loadXML animated:YES];
}
The app falls over, highlighting the tempFullUrl = url.stringValue; line but doesn't say why! I assume as the var tempFullUrl is being set weirdly
Any help would be appreciated
Tom
You're not going through your synthesised accessor, so the string is getting released. Use
self.tempFullURL =
Instead of assigning to the ivar directly. In your case it looks like the area of memory has been reassigned to a gesture recogniser which is showing up in your log statements.

iPhone crash log

do you explain the foollowing crash log......
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController createAddressBookCopy]: unrecognized selector sent to instance 0x5908300'.
what does it mean?
my code is here....
-(NSString *)pathOfFile{
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDirectory=[paths objectAtIndex:0];
//lastName.text=[paths objectAtIndex:0];
return [documentsDirectory stringByAppendingFormat:#"contacts.plist"];
}
-(IBAction)createAddressBookCopy{
UIActionSheet *actionSheet=[[UIActionSheet alloc]
initWithTitle:#"Wanna create a copy of Addressbook?"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:#"Yeah!!!"
otherButtonTitles:nil];
[actionSheet showInView:self.view];
[actionSheet release];
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
NSMutableArray *masterList = [[NSMutableArray alloc] init];
for (int i = 0; i < nPeople; i++) {
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
CFStringRef fName = ABRecordCopyValue(ref, kABPersonFirstNameProperty);
CFStringRef lName = ABRecordCopyValue(ref, kABPersonLastNameProperty);
NSString *contactFirstLast = [NSString stringWithFormat: #"%#", (NSString *)lName];
CFRelease(fName);
CFRelease(lName);
[masterList addObject:contactFirstLast];
//[contactFirstLast release];
}
//self.list = masterList;
[masterList writeToFile:[self pathOfFile] atomically:YES];
[masterList release];
}
//creating action sheet
-(void)actionSheet:(UIActionSheet *) actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex{
if (buttonIndex!=[actionSheet cancelButtonIndex]) {
UIAlertView *alert=[[UIAlertView alloc]
initWithTitle:#"Copy creaeted."
message:#"New copy is contacts.plist"
delegate:self
cancelButtonTitle:#"DONE"
otherButtonTitles:nil
];
[alert show];
[alert release];
}
}
Check if your IBAction is connected properly. I think its not connected properly. Check if the declaration of the method in .h file is same.
You have sent the message createAddressBookCopy to a UIViewController object. The app crashed because UIViewController does not have a method of that name.
It means that you have some code that tried to call the createAddressBookCopy method on a UIViewController instance. According to the documentation, no such method exists, hence the crash.
That means that some object in your program trying to send createAddressBookCopy message to UIViewController, but this UIViewController object doesn't implement such method
UIViewController doesn't have a method called createAddressBookCopy. I suspect you have a UIViewController subclass which does have that method, but for some reason you're calling the super class. This sometimes happens if you're using interface builder and don't have your outlets hooked up correctly.

How to declare an NSString with multiple possible values

I want to declare an NSString object to use within an alert, but its actual content depends on various factors, determined by some variable. I'm wondering how best to approach this. In most cases I've done something like this:
- (void)info {
NSString *targetString = [[NSString alloc] init];
switch (self.target) {
case 1:
targetString = #"ONE";
break;
case 2:
targetString = #"TWO";
break;
case 3:
targetString = #"THREE";
break;
default:
targetString = #"";
break;
}
NSString *message = [[NSString alloc] initWithFormat:#"Text: %#", targetString];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Info"
message:message
delegate:self
cancelButtonTitle:#"Ok!"
otherButtonTitles:nil];
alert.tag = kInfoAlert;
[alert show];
[alert release];
[targetString release];
[message release];
}
However when I run this through the build analyser, I get messages telling me the string is leaking memory:
First of all it says:
Value stored to 'targetString' during
its initialization is never read
Then:
Potential leak of an object allocated
on line 137 and stored into
'targetString'
These 2 comments are at line 136 and 137, where line 136 is
NSString *targetString = [[NSString alloc] init];
An alternative might be to declare the string as
NSString *targetString;
and set it in each case as
targetString = [NSString stringWithFormat:#"ONE"];
etc
Or even allocing the String in each case in order to release it at the end...
Well, what would be the best approach here?
Thanks,
Michael :)
The reason for your memory leak is because you are needlessly allocating a string with this line
NSString *targetString = [[NSString alloc] init];
and then setting it to a literal object. Define targetString as nil because when you set it to another value like targetString = #"ONE" you are no longer referencing the empty string you allocated and that causes a memory leak. As for your approach of the switch case for determining the value that is fine.
I believe this would be enough:
NSString *targetString = nil;
And you don't need to release targetString then.
How about this instead of the switch:
- (NSString*) stringForIndex: (NSUInteger) index
{
NSParameterAssert(index < 4);
id strings[] = {#"none", #"one", #"two", #"three"};
return strings[index];
}