Bug 7643 - List of DateTime? loses values in a particular situation
Summary: List of DateTime? loses values in a particular situation
Status: RESOLVED INVALID
Alias: None
Product: iOS
Classification: Xamarin
Component: XI runtime ()
Version: 5.4.x
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2012-10-04 09:13 UTC by steott
Modified: 2012-10-04 18:25 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
UIPickerDataSource.txt (1.49 KB, text/plain)
2012-10-04 09:14 UTC, steott
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED INVALID

Description steott 2012-10-04 09:13:04 UTC
Hi,
since MonoTouch 5.4 I have a problem with a particular situation (I even tried the 6.3 beta).
The problem appears only on a real device: on the simulator, it works as expected.
Everything works correctly up to MonoTouch 5.2.13.

Unluckily I haven't been able to isolate the problem in a proper sample app, so at the moment I can just try to describe the situation.

I've created a base class to handle UIPickerView Models, UIPickerDataSource (you find it as attachment).
Basically, it's just an abstract generic class, containing a list of the elements that will be showed in the UIPickerView:

public abstract class UIPickerDataSource<TItem> : UIPickerViewModel

I have 3 implementations of this abstract class. 
One is this, containing a list of DateTime? :

        public class AvailabilityDatesDataSource : UIPickerDataSource<DateTime?>
        {
            public AvailabilityDatesDataSource(UIPickerView pickerView)
                : base(pickerView)
            {
            }

            public override string GetItemTitle(DateTime? item)
            {
                if (!item.HasValue)
                    return "---";
                return item.Value.ToLongDateString();
            }
        }

The other implementations uses as generic argument a POCO class.

In a form I have only a UIPickerView that uses AvailabilityDatesDataSource as Model, in this way:

***
DatesSelectorDataSource = new AvailabilityDatesDataSource(DateSelector);
DatesSelectorDataSource.SetData(ViewModel.AvailabilityDates);
***

ViewModel.AvailabilityDates is just a IEnumerable<DateTime?>

When I run the app in the simulator, I can see in the UIPickerView all the dates with the proper values (in the tested situation, none of the elements in the ViewModel.AvailabilityDates is null).

When I run the app on the device, with the same data, I can see that the values exists in ViewModel.AvailabilityDates before calling DatesSelectorDataSource.SetData, but then the values become null when the method GetItemTitle of AvailabilityDatesDataSource  is called (that is, the list contains always the same number of elements, e.g. 2 dates, but at some point they become null).

Just for testing purposes, if I change AvailabilityDatesDataSource from DateTime? to DateTime, the values are showed correctly.

As already stated, if I compile the same code with MonoTouch 5.2.13, also on the device I get the expected behavior.

I did also another test: I entirely copied the class UIPickerDataSource, calling the new one UIPickerDataSource2, and I changed AvailabilityDatesDataSource so that it inherits from  UIPickerDataSource2 instead of UIPickerDataSource.
At this point, everything works!
I guess that some problems are caused by the fact that other classes inherits from UIPickerDataSource.

Have you got any idea about this problem?
Comment 1 steott 2012-10-04 09:14:02 UTC
Created attachment 2686 [details]
UIPickerDataSource.txt
Comment 2 Rolf Bjarne Kvinge [MSFT] 2012-10-04 09:22:31 UTC
You're creating a generic subclass of an exported class:

public abstract class UIPickerDataSource<TItem> : UIPickerViewModel

This is not supported, and may lead to all sorts of inexplicable behavior. I suggest you try making those classes non-generic (you can use Monotouch 6.0.3 to detect all cases where this happens - you'll get an error at build time).

See also bug #7390.

If it still fails without any generics, please reopen this bug report.
Comment 3 steott 2012-10-04 09:39:58 UTC
Thanks for the (very) quick response!

Ok, I will try without generics, hoping I don't have to change too much code.
I have also other controls in this way, and I've seen the error MT4112 in MonoTouch 6.0.2, signaled as a warning in 6.0.3: did you refer to this, when you say "error at build time" ?

PS: I cannot open bug #7390, it says "Access Denied"
Comment 4 Rolf Bjarne Kvinge [MSFT] 2012-10-04 09:58:33 UTC
Yes, it's the MT4112 message you can use to ensure you're not exporting any generic methods.

And I meant to point at bug #7547 (which is the but about the MT4112 error), not 7390.
Comment 6 Rolf Bjarne Kvinge [MSFT] 2012-10-04 18:25:22 UTC
We do understand that generic subclasses of NSObject is (unfortunately) quite common (we should never have allowed it in the first place, but it's a bit late for that now). The issue is that generics significantly increases the complexity of the interaction between ObjectiveC and managed code, and it will be a significant effort for us to support it properly - and for this reason I do not recommend that you wait for it. Even if we did start right away on it it would take several months before it would reach even a beta release.

However I have a few ideas which may or may not help you in the meantime if you're willing to try it out (remember that "it may fail/crash inexplicably at any time" still applies):

1) Don't instantiate generic types, create specialized non-generic subclasses of those types. Example:

var obj = new UIPickerDataSource<DateTime?> (); // BAD
var obj = new AvailabilityDatesDataSource (); // BETTER

Make all your generic classes (such as UIPickerDataSource) abstract, and the compiler will enforce this for you.

2) Specialize methods as much as possible - do not operate on type parameters in the generic classes, but instead do it in specialized methods in the derived non-generic subclasses.

// BAD:
class Bad<T> : NSObject
{
    void BadMethod (T param)
    {
        // Do something with param
    }
}

// BETTER
abstract class Base<T> : NSObject
{
    virtual abstract void Method (T param);
}

class Derived : Base<object>
{
   override void Method (object param)
   {
      // Do something with param
   }
}

Again, if you make methods abstract the compiler will help you with this.