UIPageViewController does not release the at last displayed dialog - ios

I am presenting a simple UIPageViewController and adding some really simple and stupid child view controllers to it. When the UIPageViewController gets dismissed I am disposing all child view controllers, the ones currently not displayed (listed in ChildViewControllers) and the one displayed (listed in ViewControllers). The not displayed ones get released, the displayed one gets not.
I have broken this down to a simple failing test, so I am sure it's not about the content of the child view controllers or some other issues around that. I have no idea what is retaining it.
Sample:
Master (presented)
public class MasterDialog : UIPageViewController
{
public event EventHandler OnDialogClosed;
private UIBarButtonItem _backButton;
public MasterDialog() : base(
UIPageViewControllerTransitionStyle.Scroll,
UIPageViewControllerNavigationOrientation.Horizontal,
UIPageViewControllerSpineLocation.None,
25)
{
_backButton = new UIBarButtonItem(UIBarButtonSystemItem.Cancel);
_backButton.Clicked += Close;
NavigationItem.SetLeftBarButtonItem(_backButton, false);
}
public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(animated);
OnDialogClosed(this, EventArgs.Empty);
}
private void Close(object sender, EventArgs arguments)
{
_backButton.Clicked -= Close;
NavigationController.DismissViewController(true, null);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Console.WriteLine("Master disposed");
}
}
Master Data Source
public class DataSource : UIPageViewControllerDataSource
{
public override UIViewController GetPreviousViewController(
UIPageViewController pageViewController, UIViewController referenceViewController)
{
var detail = (DetailDialog)referenceViewController;
if (detail.Page - 1 == 0)
return null;
return GetViewController(detail.Page - 1);
}
public override UIViewController GetNextViewController(
UIPageViewController pageViewController, UIViewController referenceViewController)
{
var detail = (DetailDialog)referenceViewController;
return GetViewController(detail.Page + 1);
}
public UIViewController GetViewController(int page)
{
return new DetailDialog(page);
}
}
Detail (Child)
public class DetailDialog : UITableViewController
{
public int Page { get; private set; }
public DetailDialog(int page) : base(UITableViewStyle.Plain)
{
Page = page;
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Console.WriteLine("Detail init: " + Page + " / " + GetHashCode());
var label = new UILabel();
label.Text = "#" + Page;
label.ContentMode = UIViewContentMode.Center;
label.Frame = new System.Drawing.RectangleF(0, 100, 320, 50);
label.BackgroundColor = UIColor.Green;
Add(label);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
Console.WriteLine("Detail disposed: " + Page + " / " + GetHashCode());
}
}
The opening dialog (starting point)
public class StartDialog : UIViewController
{
private DataSource _dataSource;
private MasterDialog _master;
public StartDialog()
{
Title = "WTF";
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
var button = new UIButton(UIButtonType.Custom);
button.SetTitle("Open", UIControlState.Normal);
button.BackgroundColor = UIColor.Green;
button.Frame = new System.Drawing.RectangleF(20, 150, 280, 44);
Add(button);
button.TouchDown += OpenMasterDialog;
}
private void OpenMasterDialog(object sender, EventArgs arguments)
{
_dataSource = new DataSource();
_master = new MasterDialog();
_master.DataSource = _dataSource;
_master.OnDialogClosed += HandleOnDialogClosed;
_master.SetViewControllers(
new [] { _dataSource.GetViewController(1) },
UIPageViewControllerNavigationDirection.Forward,
false,
null
);
NavigationController.PresentViewController(
new UINavigationController(_master),
true,
null
);
}
private void HandleOnDialogClosed(object sender, EventArgs e)
{
_dataSource.Dispose();
_dataSource = null;
Console.WriteLine("Before: " + _master.ChildViewControllers.Length +
"/" + _master.ViewControllers.Length + ")");
var childs = _master
.ChildViewControllers.ToList()
.Union(_master.ViewControllers);
foreach (UIViewController child in childs)
{
child.RemoveFromParentViewController();
child.Dispose();
}
Console.WriteLine("After: " + _master.ChildViewControllers.Length +
"/" + _master.ViewControllers.Length + ")");
_master.OnDialogClosed -= HandleOnDialogClosed;
_master.Dispose();
_master = null;
}
}

I might be misunderstanding your code/intent but in this case it seems to me that everything is almost fine. Anyway here's my findings...
Detail disposed: 1 / 36217954
After: 0/1)
Line #2 shows /1 which I assume to be the issue. This is normal because you're re-surfacing the view controller, IOW the code:
_master.ViewControllers.Length
calls the viewControllers selector on the UIPageViewController. That returns: "The view controllers displayed by the page view controller." which is still DetailDialog at that point (even if master is not displayed anymore).
This is not Xamarin specific, an ObjC application would return the same (native) instance at that same point of time.
That's explained - but it still not freed later, why ?
Under the new Dispose semantics the managed object is kept, after Dispose, as long as the native side requires it (but without a native reference so it can be natively released and, subsequently, released on the managed side).
In this case the lifecycle of the native object is not yet over (i.e. iOS still has reference to it) so it remains alive on the managed side.
_master.Dispose();
_master = null;
This removes the managed references to _master but again (same as above) it won't be freed (and neither will be DetailDialog) as long as the native _master instance is used (with native references).
So who got a reference to _master ?
NavigationController.PresentViewController(
new UINavigationController(_master),
^ That creates a UINavigationController and as long as it's alive the there are references to the others.
When I dispose of the UINavigationController (I kept it in a field) then the Master* and Detail* instances disappear from HeapShot.
_nav.Dispose();
_nav = null;

Related

UIPageViewController shows blank view controller when setting programmatically

I have a UIPageViewController in which I've implemented a caching mechanism. Practically I have a pool of view controllers that I try to reuse as much as possible when the next or previous view controller is requested in the UIPageViewControllerDataSource. So when the data source requests the previous or the next page I first check if that page has already been shown and return the appropriate view controller.
It all works fine with the default swipe gesture, and the internal method to change page. Now I need to disable the swipe gesture, so I'm not setting the data source, and instead, I have two buttons to go to the previous and next page, and using setViewControllers(_:direction:animated:completion:) to change page programmatically. It works fine when going always in the same direction, but as soon as I change it, and so I'm using a cached view controller, it shows a blank page.
The code is exactly the same as before, if not for setting the view controller programmatically. I've tried both with or without animation and the result is the same and if I remove caching it also works well. My question is, am I forgetting something? Is the UIPageViewController doing something internally that I'm not doing when the data source is assigned?
EDIT
Here's a simplified version of the code. It's a Xamarin Project, but I suppose it's understandable
public class MyPageViewController : AbstractPageViewController
{
const int CacheCapacity = 5;
public int initialItemId { get; set; }
public List<int> ItemIds { get; set; }
readonly List<ChildViewController> viewControllerCache = new List<ChildViewController>(CacheCapacity + 1);
public override void ViewDidLoad()
{
base.ViewDidLoad();
DataSource = null;
var vc = GetDocumentViewController(initialItemId);
SetViewControllers(new[] { vc }, UIPageViewControllerNavigationDirection.Forward, false, null);
var nextButtonItem = new UIBarButtonItem
{
Enabled = true
};
var previousButtonItem = new UIBarButtonItem
{
Enabled = true
};
nextButtonItem.Clicked += NextDocumentButton_Clicked;
previousButtonItem.Clicked += PreviousDocumentButton_Clicked;
var rightButtons = new UIBarButtonItem[2];
rightButtons[0] = nextButtonItem;
rightButtons[1] = previousButtonItem;
NavigationItem.SetRightBarButtonItems(rightButtons, false);
}
private void PreviousDocumentButton_Clicked(object sender, EventArgs e)
{
var referenceVc = (ChildViewController)ViewControllers.FirstOrDefault();
var referenceId = referenceVc.ItemId;
var index = ItemIds.FindIndex(dp => dp.Id == referenceId);
if (index < 1)
return;
var previousDocumentId = ItemIds[index - 1];
var vc = GetDocumentViewController(previousDocumentId);
SetViewControllers(new[] { vc }, UIPageViewControllerNavigationDirection.Reverse, false, null);
}
private void NextDocumentButton_Clicked(object sender, EventArgs e)
{
var referenceVc = (ChildViewController)ViewControllers.FirstOrDefault();
var referenceId = referenceVc.ItemId;
var index = ItemIds.FindIndex(dp => dp.Id == referenceId);
if (index < 0 || index >= ItemIds.Count)
return;
var nextDocumentId = ItemIds[index + 1];
var vc = GetDocumentViewController(nextDocumentId);
SetViewControllers(new[] { vc }, UIPageViewControllerNavigationDirection.Forward, false, null);
}
ChildViewController GetDocumentViewController(int ItemId)
{
var cachedViewController = viewControllerCache.FirstOrDefault(dvc => dvc.ItemId == ItemId);
if (cachedViewController != null)
return cachedViewController;
var vc = new ChildViewController();
vc.SetData(itemId);
viewControllerCache.Add(vc);
if (viewControllerCache.Count > CacheCapacity)
{
viewControllerCache[0].RecycleIfNeeded();
viewControllerCache.RemoveAt(0);
}
return vc;
}
}
It turned out that it was due to a recycling mechanism that was implemented in my code.
In particular, there's a forced recycling of the content of the view controller on ViewDidDisappear. I've disabled it in this case and then it works as it should. This also means that when the UIPageViewController has a data source, and is managing the child view controller directly, ViewDidDisappear is not called when changing page through swiping.

UIPageViewController bug when using camera

I'm trying to implement a Snapchat like feature where the views are navigated by the user swiping left or right. I'm using a UIPageViewController for this.
There is a problem though when I slide onto a UIImagePickerController view. The camera displays properly as the user is sliding onto that view, however when the user lets go of the screen and the view locks into place the camera fully blurs almost as if a fog layer is applied to it and then refocuses back to normal.
The weird thing is this doesn't occur if the transition style is "Page Curl". It only happens on "Scroll".
How can I stop this behaviour?
4 View Controllers in storyboard - Master, PageView, Home and Create (code for master and create below)
Thanks.
HeroMasterViewController class:
partial class HeroMasterViewController : ViewControllerBase IUIPageViewControllerDataSource
{
private UIViewController[] _heroViewControllers;
private UIPageViewController _heroPageViewController;
public HeroMasterViewController (IntPtr handle) : base (handle, Navigation.Page.HeroMaster)
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
_heroPageViewController = this.Storyboard.InstantiateViewController ("HeroPageViewController") as UIPageViewController;
_heroPageViewController.DataSource = this;
InitViewControllers ();
var startingViewController = new UIViewController[1] { _heroViewControllers [0] };
_heroPageViewController.SetViewControllers (startingViewController, UIPageViewControllerNavigationDirection.Forward, true, null);
_heroPageViewController.View.Frame = new CoreGraphics.CGRect (0, 0, this.View.Frame.Width, this.View.Frame.Size.Height);
this.AddChildViewController (_heroPageViewController);
this.View.AddSubview(_heroPageViewController.View);
_heroPageViewController.DidMoveToParentViewController(this);
}
public void InitViewControllers()
{
_heroViewControllers = new UIViewController[2];
_heroViewControllers [0] = this.Storyboard.InstantiateViewController ("HomeViewController");
_heroViewControllers [1] = this.Storyboard.InstantiateViewController ("CreateViewController");
}
public UIViewController GetPreviousViewController (UIPageViewController pageViewController, UIViewController referenceViewController)
{
var controller = referenceViewController as HeroViewControllerBase;
if (controller.Index == 0)
return null;
return _heroViewControllers[controller.Index - 1];
}
public UIViewController GetNextViewController (UIPageViewController pageViewController, UIViewController referenceViewController)
{
var controller = referenceViewController as HeroViewControllerBase;
if (controller.Index == (_heroViewControllers.Length - 1))
return null;
return _heroViewControllers[controller.Index + 1];
}
}
CreateViewController class:
partial class CreateViewController : HeroViewControllerBase
{
private Xamarin.Media.MediaPicker Picker;
private MediaPickerController MediaController;
public CreateViewController (IntPtr handle) : base (handle, Navigation.Page.HeroCreate, 1)
{
this.Picker = new Xamarin.Media.MediaPicker();
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
DisplayPicker ();
}
private void DisplayPicker()
{
if (this.MediaController != null)
return;
this.MediaController = this.Picker.GetTakePhotoUI(new StoreCameraMediaOptions
{
Name = DateTime.Now.ToFileTimeUtc() + ".jpg",
Directory = "MediaPickerSample"
});
this.MediaController.AllowsEditing = false;
this.MediaController.ShowsCameraControls = false;
this.MediaController.AllowsImageEditing = false;
this.MediaController.CameraDevice = UIImagePickerControllerCameraDevice.Front;
this.MediaController.View.Frame = new CGRect (0, 0, this.View.Frame.Width, this.View.Frame.Height);
var translate = CGAffineTransform.MakeTranslation (0, 71.0f);
this.View.AddSubview(this.MediaController.View);
}
}

MvvmCross ViewModel transition from the left

I am developing an app for iOS using MvvmCross. On one of my Views I have some basic report data that is displayed in a tableview.
When the table row is touched a new view containing a detail report is displayed by making the call to ShowViewModel passing some parameters in a Dictionary. This works fine.
When the user swipes left or right the app needs to show the detail report for the next or previous item in the original list. I am doing this by updating some parameters and calling ShowViewModel again. The logic behind this is all working fine.
My problem; ShowViewModel animates the new view coming in from the right. This is perfect when the user has swiped left. However when swiping right it seems counter intuitive. How can I make ShowViewModel animate or transition in from the left side?
if you look to the MvvmCross source code here you see how the default behavior is showing the ViewControllers
You need to change that by doing something like the following:
How to change the Push and Pop animations in a navigation based app
for that, one idea is to have a custom view presenter and catch navigation to that particular view-model (override Show(IMvxTouchView view) )
or, maybe derive from UINavigationController, set it to MvvmCross to use it (look to the MvxSetup), and on some events change transition to that particular view
similar to this question
How to specify view transitions on iPhone
This is the solution I was able to come up with following the helpful pointers in the answer from Andrei N. In the end I opted for a TransitionFlipFromRight and TransitionFlipFromLeft when scrolling between detail reports. Hopefully it is useful to somebody else.
I already had a presenter class that was inherited from MvxModalSupportTouchViewPresenter
public class BedfordViewPresenter : MvxModalSupportTouchViewPresenter
Within this class I added a property of MvxPresentationHint.
private MvxPresentationHint _presentationHint;
In the override of method ChangePresentation the above property is used to store the passed in parameter
public override void ChangePresentation (MvxPresentationHint hint)
{
_presentationHint = hint;
base.ChangePresentation (hint);
}
Two new MvxPresentationHint class were declared (see later)
In the presenter class the Show method was overridden
public override void Show(IMvxTouchView view)
{
if (_presentationHint is FlipFromRightPresentationHint) {
var viewController = view as UIViewController;
MasterNavigationController.PushControllerWithTransition (viewController, UIViewAnimationOptions.TransitionFlipFromRight);
}
else
if (_presentationHint is FlipFromLeftPresentationHint) {
var viewController = view as UIViewController;
MasterNavigationController.PushControllerWithTransition (viewController, UIViewAnimationOptions.TransitionFlipFromLeft);
}
else {
base.Show (view);
}
_presentationHint = null;
}
A new class that provides extensions to a UINavigationController was created with the method PushControllerWithTransition
public static class UINavigationControllerExtensions
{
public static void PushControllerWithTransition(this UINavigationController
target, UIViewController controllerToPush,
UIViewAnimationOptions transition)
{
UIView.Transition(target.View, 0.75d, transition, delegate() {
target.PushViewController(controllerToPush, false);
}, null);
}
}
All that needs to be defined now are the two new MvxPresentationHint class derivations. These belong in your Core class library project rather than the iOS application project.
public class FlipFromLeftPresentationHint : MvxPresentationHint
{
public FlipFromLeftPresentationHint ()
{
}
}
and
public class FlipFromRightPresentationHint: MvxPresentationHint
{
public FlipFromRightPresentationHint ()
{
}
}
I hope this is a help to someone else trying to do something similar
Share my solution for android:
On view:
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = base.OnCreateView(inflater, container, savedInstanceState);
var layout = view.FindViewById<LinearLayout>(Resource.Id.swippeable);
var swipeListener = new SwipeListener(this.Activity);
swipeListener.OnSwipeLeft += (sender, e) => this.ViewModel.LeftCommand?.Execute(); //Here use command into view model
swipeListener.OnSwipeRight += (sender, e) => this.ViewModel.RightCommand?.Execute();
layout.SetOnTouchListener(swipeListener);
return view;
}
Gesture listener:
public class SwipeListener : SimpleOnGestureListener, View.IOnTouchListener
{
private const int SWIPE_THRESHOLD = 100;
private const int SWIPE_VELOCITY_THRESHOLD = 100;
private readonly GestureDetector gestureDetector;
public SwipeListener(Context ctx)
{
this.gestureDetector = new GestureDetector(ctx, this);
}
public Boolean OnTouch(View v, MotionEvent e)
{
return this.gestureDetector.OnTouchEvent(e);
}
public event EventHandler OnSwipeRight;
public event EventHandler OnSwipeLeft;
public event EventHandler OnSwipeTop;
public event EventHandler OnSwipeBottom;
public override Boolean OnDown(MotionEvent e)
{
return true;
}
public override Boolean OnFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
{
Boolean result = false;
float diffY = e2.GetY() - e1.GetY();
float diffX = e2.GetX() - e1.GetX();
if (Math.Abs(diffX) > Math.Abs(diffY))
{
if (Math.Abs(diffX) > SWIPE_THRESHOLD && Math.Abs(velocityX) > SWIPE_VELOCITY_THRESHOLD)
{
if (diffX > 0)
{
SwipeRight();
}
else
{
SwipeLeft();
}
result = true;
}
}
else if (Math.Abs(diffY) > SWIPE_THRESHOLD && Math.Abs(velocityY) > SWIPE_VELOCITY_THRESHOLD)
{
if (diffY > 0)
{
SwipeBottom();
}
else
{
SwipeTop();
}
result = true;
}
return result;
}
public void SwipeRight()
{
this.OnSwipeRight?.Invoke(this, EventArgs.Empty);
}
public void SwipeLeft()
{
this.OnSwipeLeft?.Invoke(this, EventArgs.Empty);
}
public void SwipeTop()
{
this.OnSwipeTop?.Invoke(this, EventArgs.Empty);
}
public void SwipeBottom()
{
this.OnSwipeBottom?.Invoke(this, EventArgs.Empty);
}
}

JavaFX and listener memory leaks

I'm a bit confused about JavaFx 8 and the listener memory leak problem. The official doc says:
The ObservableValue stores a strong reference to the listener which will prevent the listener from being garbage collected and may result in a memory leak.
I would like to have an example where the usage of ObservableValue<T> addListener method create a memory leak.
For example, if I have a class like this:
public class ConfigurationPane extends AnchorPane {
#FXML
private Label titleLabel;
public ConfigurationPane () {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("view/ConfigurationPane .fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
#FXML
private void initialize() {
titleLabel.sceneProperty().addListener(new MyListener());
}
}
Can I get memory leaks? When a ConfigurationPane object is garbage collected, the MyListener object is garbage collected too? I'm not able to see a scenario where
a strong reference to the listener will prevent the listener from being garbage collected
P.S. I see other S.O. questions about this but none of these helped me to understand the problem.
Thanks.
It means that map which store your listener is not using weak references, and you have to remove listeners youself to avoid memory leaks.
In the example below LeakingListener objects will never be freed although corresponding TextFields being removed from scene:
public class LeakListener extends Application {
private static class LeakingListener implements InvalidationListener {
private final TextField tf;
private final int[] placeHolder = new int[50000]; // to simplify monitoring
public LeakingListener(TextField tf) {
this.tf = tf;
}
public void invalidated(Observable i) {
tf.setText(tf.getText() + ".");
}
}
#Override
public void start(Stage primaryStage) {
final Pane root = new VBox(3);
final Button btnType = new Button("Type in all");
Button btnAdd = new Button("Add");
btnAdd.setOnAction((e) -> {
TextField tf = new TextField();
root.getChildren().add(tf);
// memory leaking listener which never gets cleaned
btnType.armedProperty().addListener(new LeakingListener(tf));
});
Button btnRemove = new Button("Remove");
btnRemove.setOnAction((ActionEvent e) -> {
// find random TextEdit element
Optional<Node> toRemove = root.getChildren().stream().filter((Node t) -> t instanceof TextField).findAny();
// if any, and remove it
if (toRemove.isPresent()) {
root.getChildren().remove(toRemove.get());
}
});
Button btnMemory = new Button("Check Memory");
btnMemory.setOnAction((e) -> {
System.gc();
System.out.println("Free memory (bytes): " + Runtime.getRuntime().freeMemory());
});
root.getChildren().addAll(btnAdd, btnRemove, btnType, btnMemory);
Scene scene = new Scene(root, 200, 350);
primaryStage.setScene(scene);
primaryStage.show();
}
}
If ObservableValue stores weak reference to a listener, you wouldn't have a problem. It can be mimicked by next example:
public class LeakListener extends Application {
private static class NonLeakingListener implements InvalidationListener {
// we need listener to don't hold reference on TextField as well
private final WeakReference<TextField> wtf;
private final int[] placeHolder = new int[10000];
public NonLeakingListener(TextField tf) {
this.wtf = new WeakReference<>(tf);
}
public void invalidated(Observable i) {
if (wtf.get() != null) {
wtf.get().setText(wtf.get().getText() + ".");
}
}
}
#Override
public void start(Stage primaryStage) {
final Pane root = new VBox(3);
final Button btnType = new Button("Type in all");
// Here is rough weak listeners list implementation
WeakHashMap<TextField, NonLeakingListener > m = new WeakHashMap<>();
btnType.armedProperty().addListener((e)-> {
for (TextField tf : m.keySet()) {
m.get(tf).invalidated(null);
}
});
Button btnAdd = new Button("Add");
btnAdd.setOnAction((e) -> {
TextField tf = new TextField();
root.getChildren().add(tf);
m.put(tf, new NonLeakingListener(tf));
});
Button btnRemove = new Button("Remove");
btnRemove.setOnAction((e) -> {
// find random TextEdit element
Optional<Node> toRemove = root.getChildren().stream().filter((Node t) -> t instanceof TextField).findAny();
// if any, and remove it
if (toRemove.isPresent()) {
root.getChildren().remove(toRemove.get());
}
});
Button btnMemory = new Button("Check Memory");
btnMemory.setOnAction((e)-> {
System.gc();
System.out.println("Free memory (bytes): " + Runtime.getRuntime().freeMemory());
});
root.getChildren().addAll(btnAdd, btnRemove, btnType, btnMemory);
Scene scene = new Scene(root, 200, 350);
primaryStage.setScene(scene);
primaryStage.show();
}
}

How to switch the views form address book to mailing view

This might be a trivial thing but I am new to xamarin/monotouch or iPhone/IOS development,
I am trying to make an application(sort of gallery+mail) in which I want to share the image.At longpress
it should open the contacts from where I can select the person from contact and it should take me to the
mailing view. I do not want to do this usung "pushview", but want to just switch the views using "PresentModalViewController"
Now I am getting the addressbook but as soon as I select the contact person instead of displaying the
mailing view it goes back to the homeview.
I even tried dismissing the view after the mailing view is dismissed but the output is still the same..
please help out with this.
what I am doing is as follows:(just merged the two programs given on Xamarin website)
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.AddressBookUI;
using MonoTouch.MessageUI;
namespace ChooseContact
{
public partial class ChooseContactViewController : UIViewController
{
public ChooseContactViewController () : base ("ChooseContactViewController", null)
{
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
ABPeoplePickerNavigationController _contactController;
UIButton _chooseContact;
UILabel _contactName;
_chooseContact = UIButton.FromType (UIButtonType.RoundedRect);
_chooseContact.Frame = new RectangleF (10, 10, 200, 50);
_chooseContact.SetTitle ("Choose a Contact", UIControlState.Normal);
_contactName = new UILabel{Frame = new RectangleF (10, 70, 200, 50)};
View.AddSubviews (_chooseContact, _contactName);
_contactController = new ABPeoplePickerNavigationController ();
_chooseContact.TouchUpInside += delegate {
this.PresentModalViewController (_contactController, true); };
_contactController.SelectPerson += delegate(object sender, ABPeoplePickerSelectPersonEventArgs e) {
//_contactName.Text = string.Format(e.Person.GetEmails());
_contactName.Text = String.Format ("{0} {1}", e.Person.FirstName, e.Person.LastName);
_contactController.DismissModalViewControllerAnimated (true);
MFMailComposeViewController _mailController;
string[] Emailid = {"hz#gmail.com"};
_mailController = new MFMailComposeViewController ();
_mailController.SetToRecipients (Emailid);
_mailController.SetSubject ("mail test");
_mailController.SetMessageBody ("this is a test", false);
_mailController.Finished += ( object s, MFComposeResultEventArgs args) => {
Console.WriteLine (args.Result.ToString ());
args.Controller.DismissModalViewControllerAnimated (true);
};
this.PresentModalViewController (_mailController, true);
};
}
public override void ViewDidUnload ()
{
base.ViewDidUnload ();
// Clear any references to subviews of the main view in order to
// allow the Garbage Collector to collect them sooner.
//
// e.g. myOutlet.Dispose (); myOutlet = null;
ReleaseDesignerOutlets ();
}
public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
}
}
Try removing this line
_contactController.DismissModalViewControllerAnimated (true);

Resources