iOS c # добавление данных JSON в tableView - PullRequest
0 голосов
/ 11 октября 2019

Я не могу понять это. Кажется, что все данные попадают в список countryNames, но из функции GetCountries () список выглядит пустым. Любая помощь будет принята с благодарностью. Когда я распечатываю список на консоли в функции GetCountries, он распечатывает все данные, но за пределами списка пуст.

namespace Test
{
  public partial class StartViewController : UIViewController
  {
    private List<String> countryNames;
    //private List<String> countryLanguages;

    public StartViewController() : base("StartViewController", null)
    {
        countryNames = new List<String>();
        GetCountries();

        // function to get country names and languages
        async Task GetCountries()
        {
            List<CountryInfo> countries;
            countries = await RefreshDataAsync();

            foreach (var c in countries)
            {
                countryNames.Add(c.name);
            }
        }

    }

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        // Perform any additional setup after loading the view, typically from a nib.
        CountriesTableView.Source = new StartViewController.TableSource(countryNames, this);
    }

    public override void DidReceiveMemoryWarning()
    {
        base.DidReceiveMemoryWarning();
        // Release any cached data, images, etc that aren't in use.
    }

    public override void ViewDidAppear(bool animated)
    {
        base.ViewDidAppear(animated);
    }

    #region TableView source stuff
    public class TableSource : UITableViewSource
    {
        StartViewController vc;
        private List<String> countries;
        //private List<String> languages;

        public TableSource(List<String> countriesIn, StartViewController vc_in)
        {
            countries = countriesIn;
            vc = vc_in;
        }

        public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
        {
            UITableViewCell cell;
            // try to get a reusable cell
            cell = tableView.DequeueReusableCell("countries");
            if (cell == null)
            {
                cell = new UITableViewCell( UITableViewCellStyle.Subtitle, "countries");
            }

            return cell;
        }

        public override nint NumberOfSections(UITableView tableView)
        {
            return 1;  
        }

        public override string TitleForHeader(UITableView tableView, nint section)
        {
            return " ";
        }

        public override nint RowsInSection(UITableView tableview, nint section)
        {
            return 1;
        }
    }
    #endregion

    // A task that calls other awaitable async methods
    public async Task<List<CountryInfo>> RefreshDataAsync()
    {

        HttpClient client;
        client = new HttpClient();

        var uri = new Uri("https://restcountries.eu/rest/v2/all");


        var response = await client.GetAsync(uri);
        List<CountryInfo> Items = null;
        if (response.IsSuccessStatusCode)
        {
            var content = await response.Content.ReadAsStringAsync();


            Items = JsonConvert.DeserializeObject<List<CountryInfo>>(content);
        }

        return Items;
    }

    #region Json helpers   use http://json2csharp.com/  paste in json or url of service and it generates classes for you
    public class Currency
    {
        public string code { get; set; }
        public string name { get; set; }
        public string symbol { get; set; }
    }

    public class Language
    {
        public string iso639_1 { get; set; }
        public string iso639_2 { get; set; }
        public string name { get; set; }
        public string nativeName { get; set; }
    }

    public class Translations
    {
        public string de { get; set; }
        public string es { get; set; }
        public string fr { get; set; }
        public string ja { get; set; }
        public string it { get; set; }
        public string br { get; set; }
        public string pt { get; set; }
        public string nl { get; set; }
        public string hr { get; set; }
        public string fa { get; set; }
    }

    public class CountryInfo
    {
        public string name { get; set; }
        public List<string> topLevelDomain { get; set; }
        public string alpha2Code { get; set; }
        public string alpha3Code { get; set; }
        public List<string> callingCodes { get; set; }
        public string capital { get; set; }
        public List<object> altSpellings { get; set; }
        public string region { get; set; }
        public string subregion { get; set; }
        public int population { get; set; }
        public List<object> latlng { get; set; }
        public string demonym { get; set; }
        public double? area { get; set; }
        public double? gini { get; set; }
        public List<string> timezones { get; set; }
        public List<object> borders { get; set; }
        public string nativeName { get; set; }
        public string numericCode { get; set; }
        public List<Currency> currencies { get; set; }
        public List<Language> languages { get; set; }
        public Translations translations { get; set; }
        public string flag { get; set; }
        public List<object> regionalBlocs { get; set; }
        public string cioc { get; set; }
    }
    #endregion
}

}

1 Ответ

0 голосов
/ 12 октября 2019

Возможно, проблема в том, что ViewDidLoad вызывается до того, как вы получите countryNames от своего веб-сервиса. GetCountries - это асинхронный метод, поэтому он возвращает Task сразу, а конструктор завершает работу и сразу же возвращается, поэтому ОС теперь может свободно вызывать ViewDidLoad, что и делает ... но вы все еще ожидаетевеб-запрос приводит к тому, что countryNames остается пустым списком при вызове CountriesTableView.Source = new StartViewController.TableSource(countryNames, this);, поэтому поле countries также является пустым списком, и именно здесь вы получаете данные для отображения в списке. Поэтому вам нужно обновить ваш источник, когда GetCountries завершится ... но у вас нет способа сделать это, так как вы не ожидаете вызова на GetCountries.

namespace Test
{
  public partial class StartViewController : UIViewController
  {
    // No need for this here, since your TableSource will be holding 
    // and providing your data
    //private List<String> countryNames;
    //private List<String> countryLanguages;

    public StartViewController() : base("StartViewController", null)
    {

        // Best Practice not to call async methods from a constructor
        // A constructor should be fast and return, after running all 
        // of its code, right away.
        //GetCountries();
    }


    public override async void ViewDidLoad()
    {
        base.ViewDidLoad();
        // Perform any additional setup after loading the view, typically from a nib.
        // Get your data and then set your source
        var countries = await RefreshDataAsync();

        var countryNames = new List<string>();
        foreach (var c in countries)
        {
            countryNames.Add(c.name);
        }

        // since you awaited the above, countryNames is now populated
        // before you set up your TableSource. 
        CountriesTableView.Source = new StartViewController.TableSource(countryNames, this); 

        // On a side note, by passing and holding onto a reference to
        // this UIViewController, you are creating a circular reference
        // which will cause a memory leak. You should not need a reference
        // to this view controller from your TableSource.             
    }
    ...
  }
  ...
}

Вот и, глядя на ваш код TableSource, вы не заполняете свою ячейку какими-либо данными. Вы получаете и возвращаете ячейку, но вы не установили никаких элементов управления пользовательского интерфейса, таких как UILabel s, текстовые (или любые другие) значения для отображения ваших данных. Также вам нужно сообщить UITableView, сколько элементов вы должны отобразить, возвращая количество элементов из метода RowsInSection. На самом деле вы говорите UITableView, что у вас есть только один предмет. Вам нужно сделать что-то вроде:

    public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
    {
        UITableViewCell cell;
        // try to get a reusable cell
        cell = tableView.DequeueReusableCell("countries");
        if (cell == null)
        {
            cell = new UITableViewCell( UITableViewCellStyle.Subtitle, "countries");
        }

         // Get data for row
         string countryName = countries[indexPath.Row];

         // Display data in the cell
         cell.TextLabel.Text = countryName;

         return cell;
    }

    public override nint RowsInSection(UITableView tableview, nint section)
    {
        // return the number of items you need to display
        return countries.Count;
    }

Если бы я был на вашем месте, у вас было бы TableSource поле List<CountryInfo> вместо List<string>. Таким образом, ваш TableSource может предоставить любые данные о стране, которые UITableView может потребовать для отображения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...