jamonholmgren / ProMotion

ProMotion is a RubyMotion gem that makes iPhone development less like Objective-C and more like Ruby.
MIT License
1.26k stars 147 forks source link

Error can't convert CommentScreen into String (TypeError) #800

Closed naiyyar closed 7 years ago

naiyyar commented 7 years ago

Hi,

Getting can't convert CommentScreen into String (TypeError) when trying to open an screen from PM::TableScreen's CustomeCell

class BlogScreen < PM::TableScreen
  def table_data
        @data = [{
            cells:
            @blogs.map do |blog|
                {
                    cell_class: CustomBlogCell,
                    height: 200,
                                    properties: {
                                            parent_view: UIView,
                                    blog: blog,
                                        bottom_view: ''"
                                   },
                }
            end
        }]
    end
end
class CustomBlogCell < PM::TableViewCell
    attr_reader :bottom_view, :parent_view
    def bottom_view=(val)
            @footer_view ||= @parent_view.append!(UIView, :footer_view) do |v|
              @reply = v.append(UIButton, :reply).on(:tap) do |_|
                  open CommentScreen.new(blog: blog, nav: true)
              end
        end
end

on reply button tap i'm getting this error. Is there any way to open a screen like this?

Thanks for the help!

jamonholmgren commented 7 years ago

@naiyyar You probably want to do this:

self.table_screen.open CommentScreen.new(blog: blog, nav: true)

Does that work?

naiyyar commented 7 years ago

Thank you @jamonholmgren for the help!

properties: {
                       screen: self
                  },
in custome cell
def screen=(val)
  @screen = val
end

@screen.open CommentScreen

This works for me.

your one line code should work as well i'll give it a try.

Thanks

jamonholmgren commented 7 years ago

Be careful of circular references in the code you're using there. Might want to use a WeakRef:

def screen=(val)
  @screen = WeakRef.new(val)
end
naiyyar commented 7 years ago

Ok Thanks I would prefer your way. looks easy

BTW, What is circular references and WeakRef ?

jamonholmgren commented 7 years ago

@naiyyar In RubyMotion, they use automatic reference counting for garbage collection. They keep track of which object instances have references to them (like var = MyObject.new) and keep them alive as long as that reference is alive. When there are no more references, they garbage collect it.

The problem is if you have a circular reference, like so:

class Foo
  def set(a)
    @foo_ref = a
  end
end

a = Foo.new
b = Foo.new
c = Foo.new
a.set(b)
b.set(c)
c.set(a)

a = nil
b = nil
c = nil

In this case, the instances a, b, and c all have references to each other. So even when you unset all three variables, those @foo_ref vars will keep the others alive forever. This results in a memory leak.

However, if you changed the internal reference to a WeakRef:

  def set(a)
    @foo_ref = WeakRef.new(a)
  end

Then it won't count those internal references, and at the end when a b and c are set to nil, the original object instances will get garbage collected, meaning no memory leaks.

Hope this helps!