Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KVO on attributes in NanoStore::Model #27

Closed
jordanmaguire opened this issue Feb 6, 2013 · 6 comments
Closed

KVO on attributes in NanoStore::Model #27

jordanmaguire opened this issue Feb 6, 2013 · 6 comments

Comments

@jordanmaguire
Copy link

Hey,

I haven't been able to get KVO working using attributes defined on a NanoStore::Model.

If I replace the attribute with an attr_accessor KVO starts working so I don't think I'm doing anything wrong initializing the KVO. EG:

# attribute :disliked # KVO doesn't register
attr_accessor :disliked # KVO works

Any idea how it is possible to fix this? My code would be much cleaner if I were able to use KVO on my model attributes.

nano-store version is 0.6.0

Let me know if you need any further information.

Thanks

@siuying
Copy link
Owner

siuying commented Feb 6, 2013

This is because the accessor of nanostore models are actually stored in the 'info' ductionary, not real properties. Perhaps you can try to use KVO on 'info' for dictionary change instead.

@jordanmaguire
Copy link
Author

It seems like you can't use KVO on hashes/dictionaries.

ie:

modelInstance.info = {} # invokes kvo
modelInstance.info["ilovekvo"] = "something" # doesn't invoke KVO
modelInstance.info = "beans" # invokes kvo

So I tried manually calling the KVO in lib/nano_store/model.rb like so:

def attribute(name)
  attributes << name

  define_method(name) do |*args, &block|
    self.info[name]
  end

  define_method((name + "=").to_sym) do |*args, &block|
    self.willChangeValueForKey(name) # here doesn't go bang
    self.info[name] = args[0]
    self.didChangeValueForKey(name) # here goes bang
  end
end

but RubyMotion goes bang with:

Method `id' created by attr_reader/writer or define_method cannot be called from Objective-C. Please define manually the method instead.

I can't continue looking tonight so I might have another crack tomorrow.

Here's a quick and dirty setup I've been testing in:

class Radio < NanoStore::Model
  attribute :id
end

class RadioObserver

  def self.test
    ro = RadioObserver.new
    ro.startObserving
    ro.radio.id = "Jordan"
  end

  def radio
    @radio ||= Radio.new
  end

  def startObserving
    radio.addObserver(self, forKeyPath:"info", options: NSKeyValueObservingOptionNew, context: nil)
    radio.addObserver(self, forKeyPath:"id", options: NSKeyValueObservingOptionNew, context: nil)
  end

###
# NSKeyValueObserving
# http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVOBasics.html
###

  # This method is invoked by the system when an observed instance is changed
  def observeValueForKeyPath(keyPath, ofObject:object, change:change, context:context)
    puts "keyPath: #{keyPath}"
  end

end

@bogardon
Copy link

@jordanmaguire have you solved the Method 'id' created by attr_reader/writer or define_method cannot be called from Objective-C. Please define manually the method instead. problem?

@jordanmaguire
Copy link
Author

Yo @bogardon, I didn't. I ended up having to change the implementation anyway so I had no need to use the KVO on the attributes.

@siuying
Copy link
Owner

siuying commented Jul 23, 2013

Sorry for late reply, I found a way to listen to the change of a key from NSMutableDictionary:

radio.addObserver(self, forKeyPath:"info.id", options: NSKeyValueObservingOptionNew, context: nil)

That should work without modifying model class.

For the Method 'id' created by attr_reader/writer or define_method cannot be called from Objective-C. error, i have no idea... we'll need consult rubymotion team. Meanwhile, I'll closing the issue.

@siuying siuying closed this as completed Jul 23, 2013
@siuying
Copy link
Owner

siuying commented Jul 23, 2013

Another workaround:

class Radio < NanoStore::Model
  attribute :id
  def id
    self.info[:id]
  end
end

... yeah that's sucks. :-/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants