My class's initialize not called
I'm sure this is an elementary question, but I have the class below. In IB, I set several NSTextField controls to this class. Everything works in the blah, blah, blah part, but strangely enough the puts "initialize dctf" never seems to be called. Any thoughts as to why? require 'strings' class DuplicateCounterTextField < NSTextField include Strings attr_accessor :splitter, :completions attr_accessor :wordCount, :duplicateCount def initialize puts "initialize dctf" @splitter = /\W+/ @wordCount = 0 @cachedWordCount = 0 @duplicateCount = 0 end # blah, blah, blah working code def textDidChange(notification) words = stringValue.split(@splitter) @wordCount = words.length @duplicateCount = @wordCount - words.uniq.length if delegate.respond_to?('controlCountDidChange:wordCount:duplicateCount:') delegate.controlCountDidChange(self, wordCount:@wordCount, duplicateCount:@duplicateCount) end end # etc. end
When reopening a Cocoa class, you should not overwrite initialize and if you were to do it anyway, don't forget to call super and to return self. The Cocoa way is to create your own initializer to end up with something like DuplicateCounterTextField.alloc.initWithDuplicate Also, remember that when initializing a Cocoa class, you need to do DuplicateCounterTextField.alloc.init - Matt On Thu, Jan 21, 2010 at 3:20 PM, steve ross <cwdinfo@gmail.com> wrote:
I'm sure this is an elementary question, but I have the class below. In IB, I set several NSTextField controls to this class. Everything works in the blah, blah, blah part, but strangely enough the
puts "initialize dctf"
never seems to be called. Any thoughts as to why?
require 'strings'
class DuplicateCounterTextField < NSTextField include Strings
attr_accessor :splitter, :completions attr_accessor :wordCount, :duplicateCount
def initialize puts "initialize dctf" @splitter = /\W+/ @wordCount = 0 @cachedWordCount = 0 @duplicateCount = 0 end
# blah, blah, blah working code
def textDidChange(notification) words = stringValue.split(@splitter) @wordCount = words.length @duplicateCount = @wordCount - words.uniq.length
if delegate.respond_to?('controlCountDidChange:wordCount:duplicateCount:') delegate.controlCountDidChange(self, wordCount:@wordCount, duplicateCount:@duplicateCount) end end
# etc. end _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
So, this class doesn't reopen a Cocoa class, it subclasses it. Same anyhow? The real problem is that the class is instantiated as a side effect of nib loading, and the only place I've been able to successfully set initial state is awakeFromNib. I either can't, or don't know how to make the nib load process call a DuplicateCounterTextField.initWithSomeCoolState method. My impression is that awakeFromNib is a poor place for setting initial state because the order in which awakeFromNib's are called is undefined (or is it?). Not to overcomplicate things, but the controller needs to be able to tweak the state of the control -- for example, to change the splitter regex. Thanks for helping out here. Steve On Jan 21, 2010, at 3:25 PM, Matt Aimonetti wrote:
When reopening a Cocoa class, you should not overwrite initialize and if you were to do it anyway, don't forget to call super and to return self. The Cocoa way is to create your own initializer to end up with something like DuplicateCounterTextField.alloc.initWithDuplicate
Also, remember that when initializing a Cocoa class, you need to do DuplicateCounterTextField.alloc.init
- Matt
On Thu, Jan 21, 2010 at 3:20 PM, steve ross <cwdinfo@gmail.com> wrote: I'm sure this is an elementary question, but I have the class below. In IB, I set several NSTextField controls to this class. Everything works in the blah, blah, blah part, but strangely enough the
puts "initialize dctf"
never seems to be called. Any thoughts as to why?
require 'strings'
class DuplicateCounterTextField < NSTextField include Strings
attr_accessor :splitter, :completions attr_accessor :wordCount, :duplicateCount
def initialize puts "initialize dctf" @splitter = /\W+/ @wordCount = 0 @cachedWordCount = 0 @duplicateCount = 0 end
# blah, blah, blah working code
def textDidChange(notification) words = stringValue.split(@splitter) @wordCount = words.length @duplicateCount = @wordCount - words.uniq.length
if delegate.respond_to?('controlCountDidChange:wordCount:duplicateCount:') delegate.controlCountDidChange(self, wordCount:@wordCount, duplicateCount:@duplicateCount) end end
# etc. end _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Sorry I replied too quickly and didn't read properly. Overwriting the init method of a Cocoa class subclass is not recommended. Here is an example of what I was suggesting: http://github.com/mattetti/phileas_frog/blob/master/image_layer.rb#L44 Which then get called there: http://github.com/mattetti/phileas_frog/blob/master/game_controller.rb#L57 In any cases, you still need to call init (or super if you overwrite initialize) and you need to return self. I hope that helps. - Matt On Thu, Jan 21, 2010 at 4:09 PM, steve ross <cwdinfo@gmail.com> wrote:
So, this class doesn't reopen a Cocoa class, it subclasses it. Same anyhow? The real problem is that the class is instantiated as a side effect of nib loading, and the only place I've been able to successfully set initial state is awakeFromNib. I either can't, or don't know how to make the nib load process call a DuplicateCounterTextField.initWithSomeCoolState method. My impression is that awakeFromNib is a poor place for setting initial state because the order in which awakeFromNib's are called is undefined (or is it?). Not to overcomplicate things, but the controller needs to be able to tweak the state of the control -- for example, to change the splitter regex.
Thanks for helping out here.
Steve
On Jan 21, 2010, at 3:25 PM, Matt Aimonetti wrote:
When reopening a Cocoa class, you should not overwrite initialize and if you were to do it anyway, don't forget to call super and to return self. The Cocoa way is to create your own initializer to end up with something like DuplicateCounterTextField.alloc.initWithDuplicate
Also, remember that when initializing a Cocoa class, you need to do DuplicateCounterTextField.alloc.init
- Matt
On Thu, Jan 21, 2010 at 3:20 PM, steve ross <cwdinfo@gmail.com> wrote:
I'm sure this is an elementary question, but I have the class below. In IB, I set several NSTextField controls to this class. Everything works in the blah, blah, blah part, but strangely enough the
puts "initialize dctf"
never seems to be called. Any thoughts as to why?
require 'strings'
class DuplicateCounterTextField < NSTextField include Strings
attr_accessor :splitter, :completions attr_accessor :wordCount, :duplicateCount
def initialize puts "initialize dctf" @splitter = /\W+/ @wordCount = 0 @cachedWordCount = 0 @duplicateCount = 0 end
# blah, blah, blah working code
def textDidChange(notification) words = stringValue.split(@splitter) @wordCount = words.length @duplicateCount = @wordCount - words.uniq.length
if delegate.respond_to?('controlCountDidChange:wordCount:duplicateCount:') delegate.controlCountDidChange(self, wordCount:@wordCount, duplicateCount:@duplicateCount) end end
# etc. end _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
So that confirms my suspicion. It's not so much a MacRuby thing as a Cocoa thing. I just don't see how to set an initial state in a class that's instantiated when a nib is loaded. I don't do the alloc.initWithWhatever. On the previous subject though, adding super/self does not cause the initialize method to be called. Hmmmmmm... On Jan 21, 2010, at 4:20 PM, Matt Aimonetti wrote:
Overwriting the init method of a Cocoa class subclass is not recommended. Here is an example of what I was suggesting:
http://github.com/mattetti/phileas_frog/blob/master/image_layer.rb#L44
Which then get called there: http://github.com/mattetti/phileas_frog/blob/master/game_controller.rb#L57
In any cases, you still need to call init (or super if you overwrite initialize) and you need to return self.
This sounds like: https://www.macruby.org/trac/ticket/250 Any subclass of a native Objective C class will fail to call initialize. I do have a fix, but I've been working on other things at the moment. I'll try to finish up and get back to 250 as soon as I can. Ed On Jan 21, 2010, at 4:33 PM, steve ross wrote:
So that confirms my suspicion. It's not so much a MacRuby thing as a Cocoa thing. I just don't see how to set an initial state in a class that's instantiated when a nib is loaded. I don't do the alloc.initWithWhatever. On the previous subject though, adding super/self does not cause the initialize method to be called. Hmmmmmm...
On Jan 21, 2010, at 4:20 PM, Matt Aimonetti wrote:
Overwriting the init method of a Cocoa class subclass is not recommended. Here is an example of what I was suggesting:
http://github.com/mattetti/phileas_frog/blob/master/image_layer.rb#L44
Which then get called there: http://github.com/mattetti/phileas_frog/blob/master/game_controller.rb#L57
In any cases, you still need to call init (or super if you overwrite initialize) and you need to return self.
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Hi Steve (et al), So, there are a couple things going on here. Cocoa classes use the concept of a "designated initializer" method, which is a name for the instance method that calls the initializer method of the superclass. This chain continues until you hit [NSObject#init]. To figure this out from the documentation: - If a class does not document an initializer method, check the superclass, and continue up the chain until you find it. - If there are multiple initializer methods, the documentation for Cocoa classes will always tell you which method is the designated initializer. In ObjC/Cocoa: If you have a subclass that requires input during initialization, you should create a new designated initializer. That method should call the designated initializer of the superclass and you should override -init to call your new designated initializer. All of this stuff is explained pretty well in Apple's Objective-C guide. In Matt's example, he creates a few initialization helper methods, but -init is still the designated initializer. In your case, NSTextField is a subclass of NSControl, and the designated initializer is (from NSControl): -initWithFrame:(NSRect)frameRect I think your subclass of NSTextField should have an -initWithFrame: method or another init method that calls super.initWithFrame: Although, if you're not supposed to call super.init in MacRuby, then I'm not sure how this is supposed to work. Last point: The one odd exception case to the initialization chain is the one you hit: NIB files! nib/xib files are basically freeze-dried collections of objects that are archived into a file. When they are restored, this is done by unarchiving the file, which uses the NSCoder methods. Most of the time if you need to do custom configuration on an object instantiated from a nib file, you should probably do that in -awakeFromNib. However, if for some reason you really need to do something during object initialization, you need to do that in initWithCoder:, since this method will be called for objects in a nib file. Brian On Thu, Jan 21, 2010 at 4:33 PM, steve ross <cwdinfo@gmail.com> wrote:
So that confirms my suspicion. It's not so much a MacRuby thing as a Cocoa thing. I just don't see how to set an initial state in a class that's instantiated when a nib is loaded. I don't do the alloc.initWithWhatever. On the previous subject though, adding super/self does not cause the initialize method to be called. Hmmmmmm... On Jan 21, 2010, at 4:20 PM, Matt Aimonetti wrote:
Overwriting the init method of a Cocoa class subclass is not recommended. Here is an example of what I was suggesting:
http://github.com/mattetti/phileas_frog/blob/master/image_layer.rb#L44
Which then get called there: http://github.com/mattetti/phileas_frog/blob/master/game_controller.rb#L57
In any cases, you still need to call init (or super if you overwrite initialize) and you need to return self.
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Brian-- Thanks for the great explanation. I'm going to have to rethink how my object achieves a known initial state. Steve On Jan 21, 2010, at 6:41 PM, Brian Chapados wrote:
Hi Steve (et al),
So, there are a couple things going on here. Cocoa classes use the concept of a "designated initializer" method, which is a name for the instance method that calls the initializer method of the superclass. This chain continues until you hit [NSObject#init]. To figure this out from the documentation:
- If a class does not document an initializer method, check the superclass, and continue up the chain until you find it. - If there are multiple initializer methods, the documentation for Cocoa classes will always tell you which method is the designated initializer.
In ObjC/Cocoa: If you have a subclass that requires input during initialization, you should create a new designated initializer. That method should call the designated initializer of the superclass and you should override -init to call your new designated initializer.
All of this stuff is explained pretty well in Apple's Objective-C guide.
In Matt's example, he creates a few initialization helper methods, but -init is still the designated initializer.
In your case, NSTextField is a subclass of NSControl, and the designated initializer is (from NSControl):
-initWithFrame:(NSRect)frameRect
I think your subclass of NSTextField should have an -initWithFrame: method or another init method that calls super.initWithFrame: Although, if you're not supposed to call super.init in MacRuby, then I'm not sure how this is supposed to work.
Last point: The one odd exception case to the initialization chain is the one you hit: NIB files!
nib/xib files are basically freeze-dried collections of objects that are archived into a file. When they are restored, this is done by unarchiving the file, which uses the NSCoder methods. Most of the time if you need to do custom configuration on an object instantiated from a nib file, you should probably do that in -awakeFromNib. However, if for some reason you really need to do something during object initialization, you need to do that in initWithCoder:, since this method will be called for objects in a nib file.
Brian
On Thu, Jan 21, 2010 at 4:33 PM, steve ross <cwdinfo@gmail.com> wrote:
So that confirms my suspicion. It's not so much a MacRuby thing as a Cocoa thing. I just don't see how to set an initial state in a class that's instantiated when a nib is loaded. I don't do the alloc.initWithWhatever. On the previous subject though, adding super/self does not cause the initialize method to be called. Hmmmmmm... On Jan 21, 2010, at 4:20 PM, Matt Aimonetti wrote:
Overwriting the init method of a Cocoa class subclass is not recommended. Here is an example of what I was suggesting:
http://github.com/mattetti/phileas_frog/blob/master/image_layer.rb#L44
Which then get called there: http://github.com/mattetti/phileas_frog/blob/master/game_controller.rb#L57
In any cases, you still need to call init (or super if you overwrite initialize) and you need to return self.
participants (4)
-
Brian Chapados
-
Edward Moy
-
Matt Aimonetti
-
steve ross