infinitered / rmq

RMQ - RubyMotionQuery
MIT License
307 stars 52 forks source link

How to get value of attribute? #323

Open augustosamame opened 8 years ago

augustosamame commented 8 years ago

Hi. I can't seem to figure this one out.

I am setting a remote_image for my UIImageView object like this:

find(:face_image).attr(remote_image: @face.picture)

it works fine.

However I can't seem to figure out a way to GET the value of the set attribute.

These all fail:

find(:face_image).attr(remote_image)
find(:face_image).attr(:remote_image)
find(:face_image).attr("remote_image")

and when doing:

find(:face_image).data

I get back a UIImageView object back which does not respond to inspect.

Any hints?

jamonholmgren commented 8 years ago

I believe the best way would be to unwrap the object and get the value directly.

find(:face_image).get.remoteImage

Not sure if that works, but give it a go.

twerth commented 8 years ago

Hmm, it's been a long time, I don't remember. @GantMan added the remote image stuff in RedPotion. data or get should return the UIImageView and if the remote_image method existed above, the method should exist there too. Assuming there is a get on that method.

According to the docs (http://docs.redpotion.org/en/latest/cookbook/images/):

To assign a remote image to a UIImageView: your_ui_image_view.remote_image = "http://bit.ly/18iMhwc"

augustosamame commented 8 years ago

your suggestion failed with:

remoteImage method does not exist for UIImageView

However unwrapping the object with get let me run .method on the returned object and there are several that look promising:

:"url=:", :"remote_image=:", :"setImageWithURL:placeholderImage:", :"setImageWithURL:", :cancelCurrentImageLoad, :imageURL, :"setImageWithURL:placeholderImage:options:", :"setImageWithURL:completed:", :"setImageWithURL:placeholderImage:completed:", :"setImageWithURL:placeholderImage:options:completed:", :"setImageWithURL:placeholderImage:options:progress:completed:", :"sd_setImageWithPreviousCachedImageWithURL:andPlaceholderImage:options:progress:completed:", :cancelCurrentArrayLoad, :"setAnimationImagesWithURLs:", :"sd_setImageWithURL:placeholderImage:options:progress:completed:", :sd_cancelCurrentImageLoad, :showActivityIndicatorView, :addActivityIndicator, :removeActivityIndicator, :sd_cancelCurrentAnimationImagesLoad, :activityIndicator, :getIndicatorStyle, :"setActivityIndicator:", :"sd_setImageWithURL:", :"sd_setImageWithURL:placeholderImage:", :"sd_setImageWithURL:placeholderImage:options:", :"sd_setImageWithURL:completed:", :"sd_setImageWithURL:placeholderImage:completed:", :"sd_setImageWithURL:placeholderImage:options:completed:", :"sd_setImageWithPreviousCachedImageWithURL:placeholderImage:options:progress:completed:", :sd_imageURL,

I'll investigate a bit further and report back if one of these worked.

augustosamame commented 8 years ago

Actually none of these work. Most return nil, even promising ones like imageURL or sd_imageURL I'm stumped.

GantMan commented 8 years ago

did you try Jamon's code? That looked right to me. Or maybe even

find(:face_image).get!.remoteImage I forget

augustosamame commented 8 years ago

Hello. Yes I tried it and got the error I indicated:

undefined method 'remoteImage' for #<UIImageView:0x114e0a0c0> (NoMethodError)

with get! i get:

undefined method 'get!' for #<RubyMotionQuery::RMQ:0x116f54060> (NoMethodError)

when I do

mp find(:face_image).get

I get:

#<UIImageView:0x11077d410>
  :@remote_image_operations   => {
  "#<UIImageView:0x11077d410>"   => #<SDWebImageCombinedOperation:0x11760d970>
}
  :@_rmq_data                 => #<RubyMotionQuery::ViewData:0x114f87380 @built=true @_view_controller=#<PlayRoundScreen:0x114f78a70> @_styles=[:face_image] @_tags={}>

when running

mp find(:face_image).get.methods

I get hundreds of methods back, but the only remote_image method I can see is printed out in this format:

:"remote_image=:"

which leads me to believe it is only a setter and not a getter? I'm not really sure. I just ran against my Ruby knowledge limit.

GantMan commented 8 years ago

From a cursory glance you're right about setter.

It looks like .image is set: https://github.com/infinitered/redpotion/blob/17af406a0bd81404676b4553e73c83bf49570e17/lib/project/ext/ui_image_view.rb#L20

So you might be able to do mp find(:face_image).get.image Keep in mind this is async, so if you run it immediately after setting, it will not work.

I don't currently have a way to test this, so I'm coding blind, heh. Forgive me if the above is wrong, but it gives you a place to look.

augustosamame commented 8 years ago

I'm running the code a few seconds after setting the image to make sure it is set. This is exactly why I require this functionality. Basically I need to start a countdown timer once a remote_image is actually shown (first I get the URL from an API and then I set the URL as a remote_image attribute), and I have no way of knowing when this exactly happens except by looking at the url set for the remote_image. Right now, I'm starting my timer 2 seconds after the call which is a horrible, potentially buggy hack.

Using this: find(:face_image).get.image as suggested

returns a UIImage object, and trying several of its methods, I'm still unable to get back the set remote_image url. However, it has got me thinking that maybe I really don't need the URL at all. I only need to know if the image has changed.

Before setting the remote_image,

find(:face_image).get.image returns #<UIImage:0x114e9f090>

whereas 3 seconds later it returns: #<UIImage:0x114e21bf0>

This means the image changed and I can start my timer. So I could use this to completely bypass this issue. Any idea how I can establish a callback or something that will let me know the image changed and trigger the timer?

GantMan commented 8 years ago

honestly, best to modify the source I linked and add an optional callback so you can do what you're looking for. At that same time you can even place an instance var for the image_url should you want to pave the way for anyone needing it. The PR would be accepted by @twerth if it is clean.

augustosamame commented 8 years ago

I believe this would work. Thanks everyone for your help. I'll look into adding the callback and send the PR.

andrewhavens commented 8 years ago

Another option which might be simpler and more explicit is to manually fetch the image (using AFMotion or SDWebImage) and set it once it has been downloaded, then do whatever you want in your callback.

augustosamame commented 8 years ago

Let me see if I understand correctly.

My current flow is:

fetch the URL and set it to @face.picture via an AFMotion API Call.

In AFMotion callback (if response is 200 OK)

set the remote_image using `find(:face_image).attr(remote_image: @face.picture)`

start countdown timer

However there is a delay between setting the image with the code above and the image actually showing, so my countdown timer starts mismatched.

Are you suggesting I can download the image via AFMotion / SDWebImage first and then set it locally? How would I go about this? I guess this would make the time mismatch nonexistent and solve my problem.