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

Returns a new instance of EventsProxy.



73
74
75
76
77
78
79
80
# File 'lib/motion/events.rb', line 73

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



91
92
93
94
95
# File 'lib/motion/events.rb', line 91

def cleanup
  off_all
  off_all_context
  true
end

#deallocObject



82
83
84
85
86
87
88
89
# File 'lib/motion/events.rb', line 82

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



116
117
118
119
120
121
# File 'lib/motion/events.rb', line 116

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



123
124
125
126
127
128
129
130
131
132
133
# File 'lib/motion/events.rb', line 123

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



135
136
137
138
139
140
141
142
143
# File 'lib/motion/events.rb', line 135

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



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

def off_all
  @events.removeAllObjects
end

#off_all_contextObject



153
154
155
156
157
158
159
160
161
162
163
# File 'lib/motion/events.rb', line 153

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)
    if object.rmext_events_proxy?
      object.rmext_events_proxy.off_context(@weak_object)
    end
  end
end

#off_context(context) ⇒ Object



149
150
151
# File 'lib/motion/events.rb', line 149

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

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



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/motion/events.rb', line 97

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



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
200
201
202
203
204
205
# File 'lib/motion/events.rb', line 165

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