How can I convert NSMutableArray into NSString? - iphone

I am trying to convert (or copy?) a NSMutableArray into a NSString. I guess my problem is
that I don't really understand the structure of a NSString. After conversion I want to
attached it in email body. Here is my code:
- (IBAction)sendEmail
{
NSLog(#"sendEmail");
[textView resignFirstResponder];
[textView1 resignFirstResponder];
if ([MFMailComposeViewController canSendMail])
{
// set the sendTo address
NSMutableArray *recipients = [[NSMutableArray alloc] initWithCapacity:1];
[recipients addObject:#"example#yahoo.com"];
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"Iphone Game"];
NSString *string = [string appendString:[NSString stringWithFormat:"%#", [viewArray objectAtIndex:i]]];
[controller setMessageBody:string isHTML:NO];
[controller setToRecipients:recipients];
[self presentModalViewController:controller animated:YES];
[controller release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert"
message:#"Your device is not set up for email." delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[alert release];
}
}

EDIT:
after reading your comment, it is pretty much clear that what you are trying to do is archiving/unarchiving an array containing objects of various kinds. So, you should try using:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
to get an NSData object that you can then send as an attachment with an email message (or in whatever other persistency layer you need).
Keep in mind that this approach will work only if the objects stored in the array support the NSCoding protocol (you can check that in the reference for each type you are using: it clearly lists all the supported protocols). Considered that you say that your object are already stored as NSData, there should be no problem. Just archive the array, so you will be able to unarchive it later, if required.
If you have some custom type that does not support NSCoding, you will need to implement it as described in Encoding and Decoding Objects.
OLD ANSWER:
I am not sure I understand your problem, but what about using componentsJoinedByString:
E.g.:
NSString *string = [viewArray componentsJoinedByString:#"\n"];
Doing like this, the content of your array (provided it is made of strings) will be presented as a list of strings. If you use description, your array will be converted into a string without giving you much control on its format (it will add curly braces and other syntactic sugar).

I suspect what you wanted to do was create a loop on all the elements in viewArray and append them to an NSString string. However, as #sergio has suggested, I think componentsJoinedByString would be a better option.
This is what your method would look like with that change, I have also cleaned up some other parts of the method. It looks like there was a memory leak, recipients, in your original version.
- (IBAction)sendEmail
{
NSLog(#"sendEmail");
[textView resignFirstResponder];
[textView1 resignFirstResponder];
if ([MFMailComposeViewController canSendMail])
{
// set the sendTo address
NSArray *recipients = [NSArray arrayWithObject:#"example#yahoo.com"];
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"Iphone Game"];
NSString *string = [viewArray componentsJoinedByString:#"\n"];
[controller setMessageBody:string isHTML:NO];
[controller setToRecipients:recipients];
[self presentModalViewController:controller animated:YES];
[controller release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert"
message:#"Your device is not set up for email."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
[alert release];
}
}
This will combine the elements of the viewArray and place a newline \n between each element. You could replace the #"\n" with #"" or #" " depending on exactly what you want to do. If the elements of the array are not NSStrings then the elements description method will be called and the output of that used in the resulting string.

Depends on the format you'd like your string to have. You could always use the array's description like this:
NSString *myString = [myArray description];

Related

Memory warning when tranfer image picked camera to one view to other

I open the camera on button click and take the image in uiimage and then transfer that uiimage to other view
But i receive memory warning when i do this 4-5 time.
Below is the code i worked for:-
-(void)imagePickerController:(UIImagePickerController*)picker_camera didFinishPickingMediaWithInfo:(NSDictionary*)info
{
[picker_camera dismissModalViewControllerAnimated:YES];
UIImage *image=[[UIImage alloc] init];
image=[info objectForKey:#"UIImagePickerControllerOriginalImage"];
[self Methodcall:image];
//Image_camera=image;
// NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];
//printf("first\n");
// [self performSelector:#selector(Methodcall) withObject:nil afterDelay:1];
//printf("ok\n");
//[apool release];
}
-(void)Methodcall:(UIImage *)image{
ImageDisplayViewController *ImageDisplayViewController_obj=[[ImageDisplayViewController alloc] initWithNibName:#"ImageDisplayViewController" bundle:nil];
ImageDisplayViewController_obj.image_FRomCamera=image;
NSLog(#"image===>%# camera==>%#",image,ImageDisplayViewController_obj.image_FRomCamera);
[self.navigationController pushViewController:ImageDisplayViewController_obj animated:YES];
// [ImageDisplayViewController_obj release];
}
-(IBAction)TakePhotoCamera:(id)sender{
#try
{
UIImagePickerController *picker_camera = [[UIImagePickerController alloc] init];
picker_camera.sourceType = UIImagePickerControllerSourceTypeCamera;
picker_camera.delegate = self;
[self presentModalViewController:picker_camera animated:YES];
[picker_camera release];
}
#catch (NSException *exception)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No Camera" message:#"Camera is not available " delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
}
}
Does any one help me out please.
Thanks in advance.
I assume you're not using ARC (is there any particular reason for this?)
Firstly, you are allocating an UIImage instance that's never used:
UIImage *image=[[UIImage alloc] init];
image=[info objectForKey:#"UIImagePickerControllerOriginalImage"];
should be changed to:
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
Next, you are not releasing ImageDisplayViewController_obj instance here:
// [ImageDisplayViewController_obj release];
Uncomment this line.
Golden rule of memory management: Always release objects you don't need any more and don't retain anything you don't need.
I would highly recommend using ARC if you're new to Obj-C and/or memory management.
Some other suggestions:
How to check existence of camera?
Avoid exceptions
Follow coding conventions - don't name your variables picker_camera (use pickerCamera), or ImageDisplayViewController_obj (use imageController or imageVC).

App crashing on changing views after login

Good morning!
I am very new to iPhone/iPad programming
My app is crashing (signal SIGABRT) after trying to change views after a Login
-(void)checkLogin {
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"LoginData" ofType:#"txt"];
NSString *myText = [NSString stringWithContentsOfFile:filePath];
//Parse lines into an NSArray;
NSArray *results= [myText componentsSeparatedByString:#"\n"];// Assumes Mac line end return
if([txtUsername.text isEqualToString: [results objectAtIndex:0]]&& [txtPassword.text isEqualToString: [results objectAtIndex:1]])
{
Clients * clients = [[Clients alloc] initWithNibName:#"clients" bundle:nil];
[self presentModalViewController:clients animated:YES];
}
else
{
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Login"
message:#"Wrong credentials"
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles:nil];
[alert show];
}
}
#end
The app is crashing at this line
[self presentModalViewController:clients animated:YES];
Thank you very much!
Clients * clients = [[AboutUs alloc] initWithNibName:#"clients" bundle:nil];
[self presentModalViewController:clients animated:YES];
I think the first line is where your app gets stuck. turn it into:
Clients *clients = [[Clients alloc] initWithNibName:#"clients" bundle:nil];
[self presentModalViewController:clients animated:YES];
This code should work, but In your question, you put a certain aboutUs in your code.
I don't know what you want to do with this from you question, but if you want to put this AboutUs controller inside your Clients controller, you should use something like:
Clients *clients = [[Clients alloc] initWithRootViewController:aboutUs];
hope this helps you
Have you tried doing it like this:
Clients *myClients = [[Clients alloc] init];
[self presentViewController:clients animated:YES completion:^(void) {
}];
It should work properly. If it still crashes, something in the Clients class is going wrong.

MFMailComposer hangs app - no crash report - happens after users upgrade iOS

EDIT: I eventually contacted Apple DTS. After I provided a stackshot from an affected user, DTS decided I should file a bug with Apple BugReporter. So, at this point, I think it's an issue with MFMailComposer, but it's unresolved. The Apple bug number is 13602051
I have a bug that has been coming up again and again in an app.
Some users who upgrade their iOS version report that they can no longer use the email export in my app, which uses MFMailComposer. The app freezes, and doesn't generate a crash report.
My code is pretty simple, and I can't reproduce the reported bug, but many users have now said this happens after an iOS update. Here is the code:
// using ARC, so no reference counting
MFMailComposeViewController* controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
#autoreleasepool {
if (gpxFilePath) {
NSData *gpx = [NSData dataWithContentsOfFile:gpxFilePath];
[controller addAttachmentData:gpx mimeType:#"text/gpx" fileName:[self cleanFileName]];
gpx = nil;
}
}
[controller setSubject:subject];
[controller setMessageBody:body isHTML:YES];
[[MAP_APP_DELEGATE mainController] presentModalViewController:controller animated:YES];
After this is called, the email view comes up, but then is unresponsive.
I'm using the next code for iOS 6.1 and it works for me.
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc]init];
mailer.mailComposeDelegate = self;
[mailer setSubject:#"subject"];
User *user = [user_array objectAtIndex:1];
NSArray *toRecipients = [NSArray arrayWithObjects:#"mail address", nil];
[mailer setToRecipients:toRecipients];
NSArray *cc = [NSArray arrayWithObjects:#"mail address", nil];
[mailer setCcRecipients:cc];
NSDictionary *dic = [one array objectAtIndex:0];
NSString *description = [dic objectForKey:#"Description"];
NSString *emailBody = description;
[mailer setMessageBody:emailBody isHTML:NO];
[self presentViewController:mailer animated:YES completion:nil];
[mailer release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Failure"
message:#"Your device doesn't support the composer sheet"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
[alert release];
}
Remember that simulator is not able to send e-mail, so alert view will be shown in this case.
Note 1: presentModalViewController is deprecated in iOS 6.0
Note 2: try to send the email without data to check if this is what causes the issue
This should solve your problem.
[[MAP_APP_DELEGATE mainController] presentModalViewController:controller animated:YES];
controller = nil;

Data Attachement in E-mail?

I save my objects in NSMutablearray in NSData formate.No i am try to attached in E-mail Body.here is code.
- (IBAction)sendEmail
{
if ([MFMailComposeViewController canSendMail])
{
NSArray *recipients = [NSArray arrayWithObject:#"example#yahoo.com"];
MFMailComposeViewController *controller = [[MFMailComposeViewController
alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"Iphone Game"];
NSString *string = [viewArray componentsJoinedByString:#"\n"];
NSString *emailBody = string;
NSLog(#"test=%#",emailBody);
[controller setMessageBody:emailBody isHTML:YES];
[controller setToRecipients:recipients];
[self presentModalViewController:controller animated:YES];
[controller release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert"
message:#"Your device is not set up for email." delegate:self
cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[alert release];
}
}
I get no error,but not see any data in E-mail.in NSLog i see this..2012-05-07 15:33:22.984 Note List[273:207] test=>]please suggest any one better solution for me how i attached my NSMutableArray data in E-mail body..
i'm not clear with your question, try this way to set your data. and check the values you are going to set before passing it to composer,
see this
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
NSString *mSubject;
if(isInvite)
{
mSubject=#"TAPP Invitation";
}
else
{
mSubject= #"TAPP email";
}
[picker setSubject:mSubject];
NSString *mBody;
if(isInvite)
{
NSString *pTappId=[[DataModel sharedDataModel] getValueForKey:USER_TAPP_ID];
NSString *currentUserName=[[DataModel sharedDataModel] getValueForKey:CURRENT_USER_NAME];
mBody=[NSString stringWithFormat:#"<HTML><BODY>Hi,<br><br>We already know one another, and I would like us to keep in touch.<br><br>Let's connect through TAPP (Download Here) a smarter, private way to exchange and manage contact information.<br><br>Join TAPP and secure your preferred, unique ID before it is too late, and then connect with me. My TAPP ID is %#.<br><br>For more information, click here<br><br>Regards,<br><br>%#</BODY></HTML>",pTappId,currentUserName];
}
else
{
mBody= [NSString stringWithFormat:#"<HTML><BODY><br /><br />Connected by <a href=http://www.mytapp.com>TAPP</a></BODY></HTML>"];
}
// Set up recipients
NSArray *toRecipients = [NSArray arrayWithObject:selectedEmailId];
//NSArray *toRecipients = [NSArray arrayWithObject:#""];
[picker setToRecipients:toRecipients];
// Attach an image to the email
//NSString *path = [[NSBundle mainBundle] pathForResource:#"rainy" ofType:#"png"];
//NSData *myData = UIImagePNGRepresentation(photo.image);
//[picker addAttachmentData:myData mimeType:#"image/png" fileName:#"abc.png"];
// Fill out the email body text
NSString *emailBody = mBody;
[picker setMessageBody:emailBody isHTML:YES];
[self presentModalViewController:picker animated:YES];
[picker release];
If you're trying to attach the data as a standard email attachment, use this:
NSData *data = UIImageJPEGRepresentation(artworkImageView.image, 0.0);
[picker addAttachmentData:data mimeType:#"image/jpeg" fileName:#"Photo.jpeg"];
The data can be whatever you want, just give an appropriate mime type and file name.
Maybe your definition of the viewArray is wrong?
In your .h file:
#property(nonatomic, retain) NSMutableArray *viewArray;
In your .m file:
#synthesize viewArray;
Please have a look at the apple docs for the method "componentsJoindedByString", because I can't found a error quite know.
My test with a viewArray initialization from the api: (works good)
- (IBAction)sendEmail {
self.viewArray = [NSArray arrayWithObjects:#"here", #"be", #"dragons", nil];
if ([MFMailComposeViewController canSendMail])
{
NSArray *recipients = [NSArray arrayWithObject:#"example#yahoo.com"];
MFMailComposeViewController *controller = [[MFMailComposeViewController
alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"Iphone Game"];
//is anything in the array?
NSLog(#"viewArray: %#", viewArray);
NSString *string = [viewArray componentsJoinedByString:#"\n"];
NSString *emailBody = string;
NSLog(#"test=%#",emailBody);
[controller setMessageBody:emailBody isHTML:YES];
[controller setToRecipients:recipients];
[self presentModalViewController:controller animated:YES];
[controller release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert"
message:#"Your device is not set up for email." delegate:self
cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[alert release];
}
}

[CFDictionary count]: message sent to deallocated instance

My app is calling the rqst_run method below in didViewLoad method but I've an error. Debugger reports the following error:
[CFDictionary count]: message sent to deallocated instance
and debug marker is placed on this line (in tableView numberOfRowsInSection method below):
if([self.listing_items count] > 0)
I don't know where this variable get released
Declared in header file (interface section):
NSMutableString *rqst_error;
NSMutableData *rqst_data;
NSMutableDictionary *listing_items;
and I defined this method in implementation:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if([self.listing_items count] > 0)
{
if([self.listing_items objectForKey:#"items"])
{
return [[self.listing_items objectForKey:#"items"] count];
}
}
}
- (void)rqst_run
{
rqst_data = [[NSMutableData data] retain];
NSMutableURLRequest *http_request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.feedserver.com/request/"]];
[http_request setHTTPMethod:#"POST"];
NSString *post_data = [[NSString alloc] initwithFormat:#"param1=%#&param2=%#&param3=%#",rqst_param1,rqst_param2,rqst_param3];
[http_request setHTTPBody:[post_data dataUsingEncoding:NSUTF8StringEncoding]];
rqst_finished = NO;
[post_data release];
NSURLConnection *http_connection = [[NSURLConnection alloc] initWithRequest:http_request];
[http_request release];
if(http_connection)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
if([rqst_data length]>0)
{
NSString *rqst_data_str = [[NSString alloc] rqst_data encoding:NSUTF8StringEncoding];
SBJsonParser *json_parser = [[SBJsonParse alloc] init];
id feed = [json_parser objectWithString:rqst_data_str error:nil];
listing_items = (NSMutableDictionary *)feed;
[json_parser release];
[rqst_data_str release];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Feed" message:#"No data returned" delegate:self cancemButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Connection Problem" message:#"Connection to server failed" delegate:self cancemButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[rqst_data setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[rqst_data appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[rqst_data release];
[connection release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[rqst_data release];
[connection release];
rqst_finished = YES;
}
NSMutableDictionary must be properly initialized before use. In your code you assign feed to listing_items and then release it. It haven't been retained so listing_items is also removed.
Try to init dictionary like this:
listing_items = [[NSMutableDictionary alloc] initWithDictionary:feed];
and all should work fine.
Instead of this
listing_items = (NSMutableDictionary *)feed;
Use this
self.listing_items = [NSMutableDictionary dictionaryWithDictionary:feed];
It's pretty clear that:
* You use the instance variable instead of the property to assign the value to listing_items
* You put an autoreleased value in this ivar.
listing_items = (NSMutableDictionary *)feed; is clearly your error because feed is an autorleased variable (and then will be deallocated at the end of the current runloop by definition.
Either declare a #property(retain) for listing_items and use it each time you want to assign (autoreleased) value to it (so that the property will manage the retain/release on assignation)
Or retain the stored value manually (but this is painful as you need not to forget to release the previous value before assigning a new one to listing_items each time... which is what the setter method does when called either directly or thru the property assignment)
i think you need to initialize your NSMutableDictionary. Right now its just a pointer pointing to feed. when feed gets released, it just points to nil.
in the viewDidLoad :
listing_items = [[NSMutableDictionary alloc] init];
or you need to retain the data:
listing_items = [(NSMutableDictionary *)feed retain];
SBJsonParser *json_parser = [[SBJsonParse alloc] init];
id feed = [json_parser objectWithString:rqst_data_str error:nil];
listing_items = (NSMutableDictionary *)feed;
[json_parser release];
When you release the json_parser, the dictionary it holds is released too.
So, as others said, you need to retain the dictionary obtained from json_parser.