Unable to assign delegate in global method - ios

I have a singleton and in it I create a custom method that is going to be used by multiple viewcontrollers. The method is to display an email composer.
-(void)emailSend:(NSString*)bodyStr inVC:(UIViewController*)vc {
if ([MFMailComposeViewController canSendMail]) {
NSString *messageBody = bodyStr;
MFMailComposeViewController *mc = [[MFMailComposeViewController alloc] init];
mc.mailComposeDelegate = vc; // <-- warning
[mc setSubject:#"Say Hello"];
[vc presentViewController:mc animated:YES completion:NULL];
}else{
// Not setup
}
}
On other viewcontrollers I call this by:
[[MySingle singleton] emailSend:#"Testing" inVc:self];
The warning message is assigning to
id __Nullable from incompatible
type UIViewController *__strong
Any way how to make it work?

You need to make some changes on your method :
From :
-(void)emailSend:(NSString*)bodyStr inVC:(UIViewController*)vc
To :
-(void)emailSend:(NSString*)bodyStr inVC:(id)vc

Related

MFMailComposeViewController memory management

I created an app in which the user uses the front camera to take pictures and emails them, and the app never goes into background for at least 8 hours; the app is displayed in an office and must be always in foreground. Everything happens in an UIViewController.
The issue is with the MFMailComposeViewController, specifically with the memory which it consumes. In Instruments - Activity Monitor there is a MailCompositionS which keeps increasing in real memory usage.
My code is:
- (void)emailPhoto
{
NSString *emailTitle;
NSString *messageBody;
MFMailComposeViewController *mc = [[MFMailComposeViewController alloc] init];
mc.mailComposeDelegate = self;
[mc setSubject:emailTitle];
[mc setMessageBody:messageBody isHTML:NO];
NSData *dataImage = UIImageJPEGRepresentation(photoView.image, 0.4);
[mc addAttachmentData:dataImage mimeType:#"image/jpeg" fileName:#"image.jpg"];
[self presentViewController:mc animated:YES completion:nil];
mc = nil;
dataImage = nil;
}
- (void) mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
[self dismissViewControllerAnimated:YES completion:^{
[self backToCamera];
}];
}
I really don't understand what could be the problem. With or without the image attachment the MailCompositionS keeps increasing in memory consumption, and because the app always stays in that UIViewController and never goes into background, the memory is never released.
PS I am not detecting any leaks.
I think you have to create a once instance of MFMailComposeViewController in a property. instead of creating an instance for each Photo. just copy the couples of lines.
self.mc = [[MFMailComposeViewController alloc] init];
mc.mailComposeDelegate = self; in
viewDidLoad() or viewWillAppear().
Good Luck

initWithNibName vs init - unexpected behaviour

I have noticed that when adding a viewController with interface builder and a nib,
That I don't have to call initWithNibName for it to pick up the associated nib, I can just call init!
Any idea why?
ie.
This:
NotificationManagementController *notificationView = [[NotificationManagementController alloc] initWithNibName:#"NotificationManagementController" bundle:nil andCurrentNotifications:nil];
and This:
NotificationManagementController *notificationView = [[NotificationManagementController alloc] init];
Both seem interchangeable....
Thus if I then call these line of code:
notificationView.delegate = self;
notificationView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:notificationView animated:YES completion:NULL];
I see all changes in the nib.
NotificationManagementController *notificationView = [[NotificationManagementController alloc] initWithNibName:#"NotificationManagementController" bundle:nil andCurrentNotifications:nil];
is simply not neccessary, and even frowned upon by some (including me).
NotificationManagementController *notificationView = [[NotificationManagementController alloc] init];
is much cleaner (and safer) in that is hides implementation details, but will effectively call initWithNibName: behind the scenes.
I like to think of it this way:
- (id)init
{
self = [[NotificationManagementController alloc] initWithNibName:#"NotificationManagementController" bundle:nil andCurrentNotifications:nil];
if (self)
{
// Initialization
}
return self;
}

Object of array in new ViewController keeps empty

I've a problem with an array.
There's an array with some objects of the class Car in my CarViewController:
...Car.h
#interface Car : NSObject
#property (nonatomic, strong) NSString *name;
..and Car.m
- (void)encodeWithCoder:(NSCoder *)coder;
{
[coder encodeObject:name forKey:#"name"];
}
- (id)initWithCoder:(NSCoder *)coder;
{
self = [[Car alloc] init];
if (self != nil)
{
name = [coder decodeObjectForKey:#"name"];
}
return self;
}
and CarViewController
Car *car1 = [Car new];
car1.name = #"A1";
...
cars = [NSArray arrayWithObjects: car1, car2, ..., nil];
But when I now try to have access to this array in NewViewController there is a problem:
- (IBAction)btn:(id)sender {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Storyboard" bundle:nil];
CarViewController *vc = (CarViewController *)[storyboard instantiateViewControllerWithIdentifier:#"CarVC"];
Car *car = [vc.cars objectAtIndex:0];
NSLog(#"%#", car.name);
}
But in the log is just written that car.name = (null).
Thanks in advance to your effort.
UPDATE:
- (IBAction)btn:(id)sender {
UINavigationController *nav = self.tabBarController.viewControllers[1];
CarViewController *vc = nav.topViewController;
Car *car = [vc.cars objectAtIndex:0];
NSLog(#"%#", car.name);
}
I've tried something (thanks to rdelmar for his effort), but the result is still the same.
if you put this code
Car *car1 = [Car new];
car1.name = #"A1";
...
cars = [NSArray arrayWithObjects: car1, car2, ..., nil];
in the viewDidLoad method of your view controller, the the result is normal because your view is not loaded yet. (the viewDidLoad method has not been called yet)
I'm not familiar with storyboards but I think when you call
CarViewController *vc = (CarViewController *)[storyboard instantiateViewControllerWithIdentifier:#"CarVC"];
it will instantiate a new ViewController. So if you try to access cars property it will be nil if this new viewController is not presented on screen
Apple Documentation
You use this method to create view controller objects that
you want to manipulate and present programmatically in your
application. Before you can use this method to retrieve a view
controller, you must explicitly tag it with an appropriate identifier
string in Interface Builder.
This method creates a new instance of the specified view controller
each time you call it.

How to add email to an existing iOS app

I created an app based on the "Tabster" sample code from Apple. The app runs great, but I want to add email to it. I created an email app. and have tried every approach I can think of, learn from a tutorial, or read, but it continually crashes. I posed the question on the Apple Dev. forum and several responses were to simply "copy the files over to the existing app. and you should be good." Obviously its not this simple. I have added the MessageUI Framework and have tried copying the files in many different ways and Im am still stuck. Its Friday and this one problem has held me up since Monday. I guess the first part is the fact that there are 2 main.m files and I have tried combining them, I have tried renaming the mail's main.m file to emailmain.m. I dont know what else to try.
Its amazing to me that all of the documentation and all of the tutorials out there about creating email within an iOS app all start off with creating a new application. What am I missing? How do I add email into a fully functioning app. I would appreciate any guidance, links to literature, or tutorials on the subject.
Any help I can get on this will be tremendously appreciated. There are several other types of things I would like to add on to it, but I cant even get email implemented into it!
Thank you for help you can provide.
John
This is the method I use all the time. It should be able to be added to ANY UIViewController simple and cleanly.
Import your framework:
#import <MessageUI/MessageUI.h>
Make sure you include your delegate in the interface:
#interface MyViewController : UIViewController <MFMailComposeViewControllerDelegate>
Then in your implementation add this method or a variation if you need it to be an IBAction or something like that:
- (void)sendEmail
{
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *email = [[MFMailComposeViewController alloc] init];
email.mailComposeDelegate = self;
[email setSubject:#"My Email Subject"];
[email setMessageBody:#"My message body." isHTML:NO];
[self presentModalViewController:email animated:YES];
} else {
UIAlertView *emailAlert = [[UIAlertView alloc] initWithTitle:#"Email Failure" message:#"Your device is not configured to send email" delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[emailAlert show];
}
}
You can call this method on button click or anything you want. It will pull up an email composer view where your user can hit send.
You need to import the MessageUI Framework. Where ever you want to use it import it in the corresponding .h file and set up the MFMailComposeViewControllerDelegate.
#import <MessageUI/MessageUI.h>
#interface ViewController : UIViewController <MFMailComposeViewControllerDelegate>
Then when you want to send a message use the following code in the .m file:
MFMailComposeViewController *mailViewController = [[MFMailComposeViewController alloc] init];
mailViewController.mailComposeDelegate = self;
// Optional Configuration Parameters to make life easier for the user
[mailViewController setSubject:subjectString];
[mailViewController setMessageBody:messageString isHTML:YES];
[mailViewController setToRecipients:recipientsArray];
// Present the VIew Controller and clean up after ourselves
[self presentModalViewController:mailViewController animated:YES];
[mailViewController release];
Add the appropriate delegate method, you can use it to dismiss the controller once the email is sent:
-(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
[self dismissModalViewControllerAnimated:YES];
}
Here Is asample code to create email with an image as attachment .you can modify it according to your needs.
-(void)createEmail
{
NSMutableString *emailBody = [[[NSMutableString alloc] initWithString:#"<html><body>"] retain];
[emailBody appendString:#"<p>Some email body text can go here</p>"];
UIImage *emailImage = [UIImage imageNamed:#"myImageName.png"];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(emailImage)];
NSString *base64String = [imageData base64EncodedString];
[emailBody appendString:[NSString stringWithFormat:#"<p><b><img src='data:image/png;base64,%#'></b></p>",base64String]];
[emailBody appendString:#"</body></html>"];
NSLog(#"%#",emailBody);
//mail composer window
MFMailComposeViewController *emailDialog = [[MFMailComposeViewController alloc] init];
emailDialog.mailComposeDelegate = self;
[emailDialog setSubject:#"My Inline Image Document"];
[emailDialog setMessageBody:emailBody isHTML:YES];
[self presentModalViewController:emailDialog animated:YES];
[emailDialog release];
[emailBody release];
}

"Tell Friend" example which allow selection multiple contact

I would like to add to my application a "Tell Friend" option which allow user to select multiple contacts to send them email. Contact need to be filtered to the one who have email address only.
does any one know such ready example that I could reuse.
I recently searching for the same problem and I found iTellAfriend. It works for me.
Download this source code from github/iTellafriend. Open zip file and inside src file drag iTellAFriend.h and iTellAFriend.m to your project. Check "Copy items into destination group folder(if needed)" and "Create group folder for any added folders"
In your appdelegate.m add #import "iTellAFriend.h"
Add following to your appdelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//[iTellAFriend sharedInstance].appStoreID = yourAppId;
[iTellAFriend sharedInstance].appStoreID = 408981381; //example
return YES;
}
Add #import "iTellAFriend.h" to your ViewController.m and anywhere in your ViewController.m call following method (preferably in a button)
if ([[iTellAFriend sharedInstance] canTellAFriend]) {
UINavigationController* tellAFriendController = [[iTellAFriend sharedInstance] tellAFriendController];
[self presentModalViewController:tellAFriendController animated:YES];
}
In iTellAFriend.m modify following
- (UINavigationController *)tellAFriendController
{
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:self.messageTitle];
[picker setMessageBody:[self messageBody] isHTML:YES];
return picker;
}
to
- (UINavigationController *)tellAFriendController
{
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
NSArray *toRecipients = [NSArray arrayWithObjects:#"xxxx#xxxx.com", #"xxxxx#xxxx.com", nil];
[picker setToRecipients:toRecipients];
[picker setSubject:self.messageTitle];
[picker setMessageBody:[self messageBody] isHTML:YES];
return picker;
}
when you click your button following scene will appear it wont send the email on simulator but on device

Resources