Class: RMExtensions::EventsProxy

Inherits:
Object
  • Object
show all
Defined in:
lib/motion/events.rb

Overview

Proxy class used to hold the actual listeners and contexts where listening and watches for the real class intended to hold the observation to be deallocated, so the events can be cleaned up.

Instance Method Summary collapse

Constructor Details

#initialize(obj) ⇒ EventsProxy



69
70
71
72
73
74
75
76
# File 'lib/motion/events.rb', line 69

def initialize(obj)
  @weak_object = WeakRef.new(obj)
  @events = NSMapTable.weakToStrongObjectsMapTable
  @listenings = NSHashTable.weakObjectsHashTable
  if ::RMExtensions.debug?
    p "CREATED EventsProxy: #{@weak_object.rmext_object_desc}"
  end
end

Instance Method Details

#cleanupObject



87
88
89
90
91
# File 'lib/motion/events.rb', line 87

def cleanup
  off_all
  off_all_context
  true
end

#deallocObject



78
79
80
81
82
83
84
85
# File 'lib/motion/events.rb', line 78

def dealloc
  @did_dealloc = true
  cleanup
  if ::RMExtensions.debug?
    p "DEALLOC EventsProxy: #{@weak_object.rmext_object_desc}"
  end
  super
end

#listening_to(object) ⇒ Object

this is called in the reverse direction than normal



112
113
114
115
116
117
# File 'lib/motion/events.rb', line 112

def listening_to(object)
  if ::RMExtensions.debug?
    p "CONTEXT:", @weak_object.rmext_object_desc, "LISTENING TO:", object.rmext_object_desc
  end
  @listenings.addObject(object)
end

#now_and_on(event, inContext: context, withBlock: block) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
# File 'lib/motion/events.rb', line 119

def now_and_on(event, inContext:context, withBlock:block)
  rmext_inline_or_on_main_q do
    res = EventResponse.new
    res.context = context
    res.value = nil
    res.target = @weak_object
    res.event = event
    block.call(res)
  end
  on(event, limit:-1, inContext:context, withBlock:block)
end

#off(event, inContext: context, withBlock: block) ⇒ Object



131
132
133
134
135
136
137
138
139
# File 'lib/motion/events.rb', line 131

def off(event, inContext:context, withBlock:block)
  return if event.nil? || block.nil?
  event = event.to_s
  context ||= self.class
  return unless context_events = @events.objectForKey(context)
  return unless context_event_blocks = context_events.objectForKey(event)
  context_event_blocks.delete block
  nil
end

#off_allObject



141
142
143
# File 'lib/motion/events.rb', line 141

def off_all
  @events.removeAllObjects
end

#off_all_contextObject



149
150
151
152
153
154
155
156
157
# File 'lib/motion/events.rb', line 149

def off_all_context
  while object = @listenings.anyObject
    if ::RMExtensions.debug?
      p "CONTEXT:", @weak_object.rmext_object_desc, "UNLISTENING TO:", object.rmext_object_desc
    end
    @listenings.removeObject(object)
    object.rmext_events_proxy.off_context(@weak_object)
  end
end

#off_context(context) ⇒ Object



145
146
147
# File 'lib/motion/events.rb', line 145

def off_context(context)
  @events.setObject(nil, forKey:context)
end

#on(event, limit: limit, inContext: context, withBlock: block) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/motion/events.rb', line 93

def on(event, limit:limit, inContext:context, withBlock:block)
  return if event.nil? || block.nil?
  event = event.to_s
  context ||= self.class
  unless context_events = @events.objectForKey(context)
    context_events = {}
    @events.setObject(context_events, forKey:context)
  end
  unless context_event_blocks = context_events.objectForKey(event)
    context_event_blocks = {}
    context_events.setObject(context_event_blocks, forKey:event)
  end
  block.weak!
  context_event_blocks[block] = limit
  # i.e.: controller/view listening_to model
  context.rmext_events_proxy.listening_to(@weak_object)
end

#trigger(event, value) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/motion/events.rb', line 159

def trigger(event, value)
  rmext_inline_or_on_main_q do
    next if @did_dealloc
    next if event.nil?
    event = event.to_s
    keyEnumerator = @events.keyEnumerator
    contexts = []
    while context = keyEnumerator.nextObject
      contexts.push context
    end
    while context = contexts.pop
      if context_events = @events.objectForKey(context)
        if event_blocks = context_events[event]
          blocks = event_blocks.keys
          if ::RMExtensions.debug?
            p "TRIGGER:", event, "OBJECT:", @weak_object.rmext_object_desc, "CONTEXT:", context.rmext_object_desc, "BLOCKS SIZE:", blocks.size
          end
          while block = blocks.pop
            limit = event_blocks[block]
            res = EventResponse.new
            res.context = context
            res.value = value
            res.target = @weak_object
            res.event = event
            block.call(res)
            if limit == 1
              # off
              if ::RMExtensions.debug?
                p "LIMIT REACHED:", event, "OBJECT:", @weak_object.rmext_object_desc, "CONTEXT:", context.rmext_object_desc
              end
              off(event, inContext:context, withBlock:block)
            elsif limit > 1
              context_events[block] -= 1
            end
          end
        end
      end
    end
  end
  nil
end