Search code examples
rubyrubymotion

How to ensure data is loaded before tableviewcontroller tries to load it


I have a UITableViewController and the problem I'm getting is NoMethodError 'length' for nil class - as @data is [] which otherwise returns rows when called in a different context , how can I ensure the data is loaded from the remote service before tableview attempts to load it?

    def viewDidLoad
        super
        loaddata
    end

    def loaddata
        @data = ().to_a
        AFMotion::Client.shared.get("api/v1/user") do |response|
        if response.success?
        d = response.object["user"]
          d.each {
           |item|
            aitem = item.new(item)
            @data << aitem
          }
       end
     end
    end

     def tableView(table_view, numberOfRowsInSection: section)                                           
         @data.length          //error here                                                                            
     end 

Solution

  • It would be (quick solution)

    def tableView(table_view, numberOfRowsInSection: section)                                           
      loaddata unless @data
      @data.length          //error here                                                                            
    end
    

    Or (more ruby-like solution, but more refactoring required):

    Change your loaddata method to:

    def loaddata
      result = [] 
      AFMotion::client.shared.get("api/v1/user") do |response|
        if response.success?
          result = response.object["user"].map { |item| item.new(item) }
        end
      end
      result
    end
    

    Define new method:

    def data
      @data ||= loaddata
    end
    

    Now use data instead of @data. It will ensure loaddata is called every time data is called for the first time and it will cache the results of that call.

    Few more points:

    1. naming convention - in ruby we use snakecase for methods and variable, so table_view instead of tableView

    2. AFMotion::client - it is really hard to parse for me. Is client a module method (then should be rather AFMotion.client) or is it a module/class (should be then AFMotion::Client)