Re: [MacRuby-devel] Problem with a window controller
Hi David and Jean-Denis, I haven't been following the list for a while so I'm just catching up and see my message about initialization sparked some responses. I haven't observed the behavior that you mention of awakeFromNib being called more than once for an object instantiated by NIB file expansion and I log calls to awakeFromNib in my applications, but I haven't used the initWithCoder method yet either. I think all all MacRuby subclass objects are custom objects and will receive an init message in addition to or in lieu of initWithCoder. I should give initWithCoder a try to reduce my app startup time. I load some data from CSV files and the Ruby CSV file parser is so incredibly slow that I have to parse the files one line at a time in an NSTimer loop to avoid getting the waiting icon and crashing my USB device drivers. A large CSV file of about 2,000 lines takes 20-30 seconds of processing time to load! I probably should pre-parse the CSV files then load the data from binary files. Do you know what would cause awakeFromNib to be called more than once for an object instance? I have considered awakeFromNib to be an initialization method and I've been using it as such without a problem. My understanding is that the NIB file expansion instantiates objects by unarchiving but then uses your attr_writer or attr_accessor construction methods to set up outlet connections and it calls setTarget and setAction methods to establish action connections before calling awakeFromNib. Bob Rice On Dec 10, 2012, at 5:38 AM, david kramf dakr@gmail.com wrote: Hi Jean-Denis 1. Thank you for your advice about awakeFromNib and InitWithCoder. 2. That is a bonus you ... This is not a bonus. This is Ruby. If you define a Ruby class you expect that any object will get instantiated through initialize. I have a feeling that all who responded to me on the forum started their programming track from Objective-C and proceeded to Ruby. I am coming from the opposite direction. I come from Ruby and wants to deal with Objective-C as little as possible. So I expect MacRuby to be as much Ruby as it is possible. Many Thanks, David On Dec 10, 2012, at 11:27 AM, Jean-Denis MUYS wrote: On 7 déc. 2012, at 19:48:39, david kramf dakr@gmail.com wrote: Message: 1 Date: Fri, 7 Dec 2012 19:48:39 +0200 From: david kramf dakr@gmail.com To: MacRuby development discussions. macruby-devel@lists.macosforge.org Subject: Re: [MacRuby-devel] Problem with a window controller Message-ID: 1f1681c7-9de6-4971-8d17-722f5ec63...@gmail.com Content-Type: text/plain; charset=us-ascii Hi Bob, As you become more familiar with IB, you will probably do more initialization of objects in IB and less in MacRuby. Nib file expansion instantiates objects and then makes calls to initialize the objects using the same methods that you are using to initialize objects in MacRuby. Actually, in a large application, it would difficult to hook up all of the outlets without using IB. From my modest acquaintance with MacRuby that is not exactly the case since when the NIB instantiates an NSWindowController object , it does not call initialize Cocoa, whether accessed from Ruby, Python, Objective-C or any language, uses the Cocoa initialization patterns. It's unrealistic to assume the framework patterns to change when you change the client language. ,as defined in Ruby , but calls awakeFromNib. It does, but caveat: awakeFromNib is *not* an initialization method, even though it is often used as such. I was bitten before. The correct initialization method to use for Nib files is initWithCoder:. What's the difference, says you (and me)? Behold: awakeFromNib can be called several times in the lifetime of an object. This is no big deals for most initializations, but becomes a major issue in others. In my case, I was registering for notifications in awakeFromNib. Since I was registered several times, I got the notifications multiple times, and since I only unsubscribed once in dealloc, my app would crash. Many cases when awakeFromNib is called more than once are programming errors, but not all. And since there *is* a real initializer, I recommend using it. So in that case why is there an awakeFromNib method at all? It is because at initWithCoder: time, IB outlets are not yet loaded and are all nil. So awakeFromNib is meant to for initialization code that configures outlet. So here is a recipe: 1- Does you initialization code requires IB outlets to be alive? If not, override initWithCoder: 2- If so, put it in awakeFromNib 3- Does that awakeFromNib initialization code need to be called once only? if so, make it conditional on it having been already be called. 4- Optional: assert that awakeFromNib was not called before, and if that assert fires, investigate whether the case is legitimate or due to a bug in your code. Only when you instantiate your
Re: [MacRuby-devel] Problem with a window controller
Hi Jean-Denis 1. Thank you for your advice about awakeFromNib and InitWithCoder. 2. That is a bonus you ... This is not a bonus. This is Ruby. If you define a Ruby class you expect that any object will get instantiated through initialize. I have a feeling that all who responded to me on the forum started their programming track from Objective-C and proceeded to Ruby. I am coming from the opposite direction. I come from Ruby and wants to deal with Objective-C as little as possible. So I expect MacRuby to be as much Ruby as it is possible. Many Thanks, David On Dec 10, 2012, at 11:27 AM, Jean-Denis MUYS wrote: On 7 déc. 2012, at 19:48:39, david kramf dakr@gmail.com wrote: Message: 1 Date: Fri, 7 Dec 2012 19:48:39 +0200 From: david kramf dakr@gmail.com To: MacRuby development discussions. macruby-devel@lists.macosforge.org Subject: Re: [MacRuby-devel] Problem with a window controller Message-ID: 1f1681c7-9de6-4971-8d17-722f5ec63...@gmail.com Content-Type: text/plain; charset=us-ascii Hi Bob, As you become more familiar with IB, you will probably do more initialization of objects in IB and less in MacRuby. Nib file expansion instantiates objects and then makes calls to initialize the objects using the same methods that you are using to initialize objects in MacRuby. Actually, in a large application, it would difficult to hook up all of the outlets without using IB. From my modest acquaintance with MacRuby that is not exactly the case since when the NIB instantiates an NSWindowController object , it does not call initialize Cocoa, whether accessed from Ruby, Python, Objective-C or any language, uses the Cocoa initialization patterns. It's unrealistic to assume the framework patterns to change when you change the client language. ,as defined in Ruby , but calls awakeFromNib. It does, but caveat: awakeFromNib is *not* an initialization method, even though it is often used as such. I was bitten before. The correct initialization method to use for Nib files is initWithCoder:. What's the difference, says you (and me)? Behold: awakeFromNib can be called several times in the lifetime of an object. This is no big deals for most initializations, but becomes a major issue in others. In my case, I was registering for notifications in awakeFromNib. Since I was registered several times, I got the notifications multiple times, and since I only unsubscribed once in dealloc, my app would crash. Many cases when awakeFromNib is called more than once are programming errors, but not all. And since there *is* a real initializer, I recommend using it. So in that case why is there an awakeFromNib method at all? It is because at initWithCoder: time, IB outlets are not yet loaded and are all nil. So awakeFromNib is meant to for initialization code that configures outlet. So here is a recipe: 1- Does you initialization code requires IB outlets to be alive? If not, override initWithCoder: 2- If so, put it in awakeFromNib 3- Does that awakeFromNib initialization code need to be called once only? if so, make it conditional on it having been already be called. 4- Optional: assert that awakeFromNib was not called before, and if that assert fires, investigate whether the case is legitimate or due to a bug in your code. Only when you instantiate your controller from the code itself , you get your initializemethod called. That is a bonus you just can be happy to have due to the deep integration of MacRuby in the Objective-C runtime system. There is no reason to assume that bonus to expand to objects created by the framework. I know I still have a lot of practicing on IB. What I find disturbing ,is that when I do something with IB I cannot see the code created to accommodate my actions ( maybe because I only work in MacRuby and not Objective-C?). No. This is simply because there **no code created**. At all. IB does't generate code. And lest I forget: Interface Builder is not a code generation tool. IB instantiates and populates objects, and then serializes them to disk. Those objects are then simply deserialized from disk in your app. At no point ever is any code generated. Therefore, there is no code created to accommodate your actions for you to see. Even in Objective-C. Best regards, Jean-Denis ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel
Re: [MacRuby-devel] Problem with a window controller
Hi Bob What I don't like is the way MacRuby supports… - I hope that MacRuby will improve on that point. I have not encountered that problem yet. myClass = MyClass.alloc.initWithArgument( argument )… - I believe this will work fine but this is not Ruby. In Ruby( to the best of my knowledge) you never allocate . You call NEW and Ruby takes care of allocating, initialization, calling your Initialize method and finally ( I hope!!) destroying and releasing the space. The programmer should never worry about that. I would expect that this behavior to be followed also when an Object is instantiated from NIB , but I can understand how implementation issues make it hard to implement. Thanks, David On Dec 8, 2012, at 9:52 AM, Robert Carl Rice wrote: Hi David, IB will use the default Obj C initialization and, yes, the default Obj C initialization is a little different from Ruby initialization so I have to make minor changes when I change a class from MacRuby instantiation to IB instantiation. The default Obj C initialization calls init with no arguments immediately after instantiation. This is the equivalent of: myClass = MyClass.alloc.init or myClass = MyClass.new. You can initialize ruby class variables in you own init method, but the init method generally should include a call to super and must return self. You could pass argument(s) to a new Obj C with the first call using something like , but it's usually easier to send a second message with arguments. Someone else here could better provide details on how MacRuby initialization maps to Obj C initialization. IB will later call awakeFromNib for all instantiated objects after it has completed initializing all instantiated objects so all of your IBOutlets will be connected. This behavior can be very convenient. You can examine an XIB file with any XML file editor for curiosity, but I haven't found any need to decode it so long as the NIB file expansion does what IB says it will do. What I don't like is the way MacRuby supports IB outlets because it becomes much too slow for large applications. It begins processing all MacRuby project files when I open the IB connections view. But it only needs to refresh the MacRuby class object that I currently have selected in IB and its MacRuby superclasses. Since filenames don't have to match class names, it would still have to scan files to find my class definition (or definitions), but that should be very much faster than processing all of the files to find and update IB Outlets. Bob Rice On Dec 7, 2012, at 12:48 PM, david kramf dakr@gmail.com wrote: Hi Bob, As you become more familiar with IB, you will probably do more initialization of objects in IB and less in MacRuby. Nib file expansion instantiates objects and then makes calls to initialize the objects using the same methods that you are using to initialize objects in MacRuby. Actually, in a large application, it would difficult to hook up all of the outlets without using IB. From my modest acquaintance with MacRuby that is not exactly the case since when the NIB instantiates an NSWindowController object , it does not call initialize ,as defined in Ruby , but calls awakeFromNib. Only when you instantiate your controller from the code itself , you get your initializemethod called. I know I still have a lot of practicing on IB. What I find disturbing ,is that when I do something with IB I cannot see the code created to accommodate my actions ( maybe because I only work in MacRuby and not Objective-C?). Thanks, David On Dec 6, 2012, at 7:42 PM, Robert Carl Rice wrote: ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel
Re: [MacRuby-devel] Problem with a window controller
Hi Bob, As you become more familiar with IB, you will probably do more initialization of objects in IB and less in MacRuby. Nib file expansion instantiates objects and then makes calls to initialize the objects using the same methods that you are using to initialize objects in MacRuby. Actually, in a large application, it would difficult to hook up all of the outlets without using IB. From my modest acquaintance with MacRuby that is not exactly the case since when the NIB instantiates an NSWindowController object , it does not call initialize ,as defined in Ruby , but calls awakeFromNib. Only when you instantiate your controller from the code itself , you get your initializemethod called. I know I still have a lot of practicing on IB. What I find disturbing ,is that when I do something with IB I cannot see the code created to accommodate my actions ( maybe because I only work in MacRuby and not Objective-C?). Thanks, David On Dec 6, 2012, at 7:42 PM, Robert Carl Rice wrote: As you become more familiar with IB, you will probably do more initialization of objects in IB and less in MacRuby. Nib file expansion instantiates objects and then makes calls to initialize the objects using the same methods that you are using to initialize objects in MacRuby. Actually, in a large application, it would difficult to hook up all of the outlets without using IB. ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel
Re: [MacRuby-devel] Problem with a window controller
Hi David, IB will use the default Obj C initialization and, yes, the default Obj C initialization is a little different from Ruby initialization so I have to make minor changes when I change a class from MacRuby instantiation to IB instantiation. The default Obj C initialization calls init with no arguments immediately after instantiation. This is the equivalent of: myClass = MyClass.alloc.init or myClass = MyClass.new. You can initialize ruby class variables in you own init method, but the init method generally should include a call to super and must return self. You could pass argument(s) to a new Obj C with the first call using something like myClass = MyClass.alloc.initWithArgument( argument ), but it's usually easier to send a second message with arguments. Someone else here could better provide details on how MacRuby initialization maps to Obj C initialization. IB will later call awakeFromNib for all instantiated objects after it has completed initializing all instantiated objects so all of your IBOutlets will be connected. This behavior can be very convenient. You can examine an XIB file with any XML file editor for curiosity, but I haven't found any need to decode it so long as the NIB file expansion does what IB says it will do. What I don't like is the way MacRuby supports IB outlets because it becomes much too slow for large applications. It begins processing all MacRuby project files when I open the IB connections view. But it only needs to refresh the MacRuby class object that I currently have selected in IB and its MacRuby superclasses. Since filenames don't have to match class names, it would still have to scan files to find my class definition (or definitions), but that should be very much faster than processing all of the files to find and update IB Outlets. Bob Rice On Dec 7, 2012, at 12:48 PM, david kramf dakr@gmail.com wrote: Hi Bob, As you become more familiar with IB, you will probably do more initialization of objects in IB and less in MacRuby. Nib file expansion instantiates objects and then makes calls to initialize the objects using the same methods that you are using to initialize objects in MacRuby. Actually, in a large application, it would difficult to hook up all of the outlets without using IB. From my modest acquaintance with MacRuby that is not exactly the case since when the NIB instantiates an NSWindowController object , it does not call initialize ,as defined in Ruby , but calls awakeFromNib. Only when you instantiate your controller from the code itself , you get your initializemethod called. I know I still have a lot of practicing on IB. What I find disturbing ,is that when I do something with IB I cannot see the code created to accommodate my actions ( maybe because I only work in MacRuby and not Objective-C?). Thanks, David On Dec 6, 2012, at 7:42 PM, Robert Carl Rice wrote: ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel
Re: [MacRuby-devel] Problem with a window controller
Hi David, You should consider the window Objective C property to be owned by NSWindowController and it's confusing to define a Ruby class variable with the same name. It should automatically appear as an IB outlet for your NSWindowController subclass that you would hook up in IB just as you would a MacRuby outlet assuming that you instantiate your NSWindowController subclass with the same NIB with your NSWindow. As per the NSWindowController documentation, you would read the window property using the method window() or self.window which will first load the window if it not already loaded. You could set the window property using setWindow( window ), but normally you have NIB expansion call setWindow. Similarly NSWindow automatically defines the delegate property that you can hook up to your window controller in IB assuming that you instantiate your NSWindowController subclass with the same NIB with your NSWindow. I removed a lot of initialization code from my applications once I better understood how NIB file expansion works. You can hook up most of your delegates and target actions in IB. You can even initialize static Popup and comboBox option lists in IB. However, don't hookup dataSource in IB for NSTableView or NSOutlineView because it will attempt to load table data before you get awakeFromNib. Bob Rice On Dec 3, 2012, at 1:35 AM, david kramf dakr@gmail.com wrote: Hi Bob My code crashes if I omit the attr_accessor. Can you refer me to instructions of how to configure the IB to link to my controller as delegate (?) . In the examples I have in my book and ,if I am not mistaken, lectures I viewed in iTunes U ( the Stanford series ), they all used the awakeFromNib as point of initialization . Thanks, David On Dec 3, 2012, at 6:24 AM, Robert Carl Rice wrote: Hi David, A couple of things I notice offhand in you code: The NSWindowController class defines accessor methods for window so you shouldn't redefine it with the Ruby attr_accessor method. Note: similarly NSViewController defines accessor methods for view. You can configure IB to link the window delegate when the Nib is expanded so that you don't need to set it in awakeFromNib. Bob Rice On Nov 29, 2012, at 6:50 PM, david kramf dakr@gmail.com wrote: Hi, In the copied below code only the awakeFromNib is executed . Can someone explain me what do I do wrong ? Window is displayed and I expected all other methods to be called. Thanks, David ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel
Re: [MacRuby-devel] Problem with a window controller
Hi Bob I never programmed in Objective-C. When I open a MacRuby project I automatically get a window attar_accessor defined in my AppDelegate created code, but not in the controller which I write by my own. If I connect, using IB , the window to my controller parameter (object variable) , I get the same window property created both in my WindowController and in the appDelegate. So far during my plays with the code I don't encounter any other problem apart from the willLoad and didLoad delegates which I expected to be called . Since the @window variable is already instantiated when my awakeFromNib is called, I have a feeling that the Cocoa code already called them before he created MyController class. I am not sure about that , since this reasoning leads to a conclusion that this is some kind of a bug in Cocoa , but Cocoa exists for a long time and used a lot , so I am not sure. Since this is the only problem I faced so far , I decided to move on and be careful upon relying on these 2 delegates. Thanks, David. On Dec 4, 2012, at 2:06 AM, Robert Carl Rice wrote: Hi David, You should consider the window Objective C property to be owned by NSWindowController and it's confusing to define a Ruby class variable with the same name. It should automatically appear as an IB outlet for your NSWindowController subclass that you would hook up in IB just as you would a MacRuby outlet assuming that you instantiate your NSWindowController subclass with the same NIB with your NSWindow. As per the NSWindowController documentation, you would read the window property using the method window() or self.window which will first load the window if it not already loaded. You could set the window property using setWindow( window ), but normally you have NIB expansion call setWindow. Similarly NSWindow automatically defines the delegate property that you can hook up to your window controller in IB assuming that you instantiate your NSWindowController subclass with the same NIB with your NSWindow. I removed a lot of initialization code from my applications once I better understood how NIB file expansion works. You can hook up most of your delegates and target actions in IB. You can even initialize static Popup and comboBox option lists in IB. However, don't hookup dataSource in IB for NSTableView or NSOutlineView because it will attempt to load table data before you get awakeFromNib. Bob Rice On Dec 3, 2012, at 1:35 AM, david kramf dakr@gmail.com wrote: Hi Bob My code crashes if I omit the attr_accessor. Can you refer me to instructions of how to configure the IB to link to my controller as delegate (?) . In the examples I have in my book and ,if I am not mistaken, lectures I viewed in iTunes U ( the Stanford series ), they all used the awakeFromNib as point of initialization . Thanks, David On Dec 3, 2012, at 6:24 AM, Robert Carl Rice wrote: Hi David, A couple of things I notice offhand in you code: The NSWindowController class defines accessor methods for window so you shouldn't redefine it with the Ruby attr_accessor method. Note: similarly NSViewController defines accessor methods for view. You can configure IB to link the window delegate when the Nib is expanded so that you don't need to set it in awakeFromNib. Bob Rice On Nov 29, 2012, at 6:50 PM, david kramf dakr@gmail.com wrote: Hi, In the copied below code only the awakeFromNib is executed . Can someone explain me what do I do wrong ? Window is displayed and I expected all other methods to be called. Thanks, David ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel
Re: [MacRuby-devel] Problem with a window controller
Thank you very much Andy and Jim I followed your remarks , played with the code and I am still surprised. It turns out that awakeFromNib is called before applicationDidFinishLaunching so there MyController is already initialized and has the correct window as the his instance variable. NSWindow has both a delegate protocol and a Controller class and so I called setDelegate and setController . Everything seems OK but the methods willLoad and didLoad are not called although clearly my class is both the delegate and the controller of my window . So I am still left asking what am I doing wrong (??). Are there MacRuby code samples I can use. I read Lim,Chueng and McAnally book. I wonder where can I find more samples. I am also not sure I am doing everything correct with the IB . My blue box that represents MyController list showWindow: as a Received Action , but I could not connect it to any element of window draw in the XIB file. David class AppDelegate attr_accessor :window def applicationDidFinishLaunching(a_notification) puts Insert code here to initialize your application wCtrl = @window.delegate puts no delegate if wCtrl == nil win = wCtrl.window puts win is nil if win == nil puts title of window is #{win.title} ctrl = @window.windowController puts no controller if ctrl == nil puts class of delegate is #{wCtrl.class} puts class of controller is #{ctrl.class} puts both are equal if wCtrl == ctrl x = ctrl.showWindow puts x class is #{x.class} unless x == nil #puts window nil if win == nil #wCtrl.close end end class MyController NSWindowController attr_accessor :window def initialize puts in initialize initWithWindowNibName(tow) #puts after initialization window is #{@window.title} end def routine puts in routine end #def initWithWindow(window) # puts in initWithWindow # super(@window) #end def awakeFromNib @window.setDelegate(self) @window.setWindowController(self) puts at end of awake from nib. title is #{@window.title} end def windowWillLoad puts window will be soon loaded end def windowDidLoad puts window loaded end def windowTitleForDocumentDisplayName(displayName) Hello World end def showWindow puts in showWindow super(self) end def close puts in close window is #{@window.title} super end end at end of awake from nib. title is two Insert code here to initialize your application title of window is two class of delegate is MyController class of controller is MyController both are equal in showWindow x class is MyController On Dec 1, 2012, at 3:00 AM, Andy Park wrote: Without being able to verify anything for accuracy at the moment, it looks like your window's delegate is not set to the controller at the time the events are occurring. Check if you need to set this - try tracing the window's delegate at different points of the controller's lifecycle. On 30 Nov 2012, at 00:50, david kramf dakr@gmail.com wrote: Hi, In the copied below code only the awakeFromNib is executed . Can someone explain me what do I do wrong ? Window is displayed and I expected all other methods to be called. Thanks, David class MyController NSWindowController attr_accessor :window def awakeFromNib @window.delegate = self puts at end of awake from nib. title is #{@window.title} end def windowWillLoad puts window will be soon loaded end def windowDidLoad puts window loaded end def windowTitleForDocumentDisplayName(displayName) Hello World end ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel ___ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo/macruby-devel