Re: ivar access during -finalize
On Mar 10, 2012, at 23:18 , Eric Wing wrote: > I don't disagree that finalizers are hard and need to be approached > with great care. And I agree that all 4 of your points are valid. > However, I think this description of the retain cycle problem might be > a little over-dramatic. Retain cycles have always been a problem in > classic memory management and are still a problem even under ARC. Yet > there is over a decade's worth of code that managed to write code to > the Cocoa framework and for the most part avoid retain cycles. With a > simple scoped problem, well defined strategy, and some care, I think > this is entirely doable. And if he were to go manual management or > ARC, he has to avoid retain cycles anyway so he still has to design > carefully. I think I'd put it this way: There's a difference between a retain cycle in a retain/release (RR) app and a retain cycle introduced into a GC app by using CFRetain. In the first case, the app is architected so that cycles are manually broken in cases where that's necessary. In the second case, the app was previously architected to *ignore* any question of cycles, since normally they're irrelevant to GC. By using CFRetain, the question is no longer irrelevant, and the app may need to be re-architected, and the changes may not be local to the places where CFRetain is explicitly used. On top of that, in a GC app, you aren't in control of all of the code (you're using Cocoa frameworks, other frameworks and libraries, whose internal use of references is unknown and unmanageable). At risk of making another sweeping generalization, I'd say that spending your time on doing complicated things with finalization is a terrible waste of resources. The finalization/resource-disposal problem is the *big* drawback to GC apps. Retain cycles are the *big* drawback to ARC apps. Both of them require considerable design and implementation effort to solve. In Jonathan's case, using CGRetain would mean he has to solve *both* at the same time. If he can't solve the finalization problem more directly, he'd probably be better off re-architecting the app for ARC and just dealing with the cycles**. But, as I noted before, he could be lucky in using your suggestion. It might be two small problems instead of two big problems. :) ** Apart from retain cycle issues, the code for GC and ARC is basically the same. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Forcing subclass creation through method swizzling not airtight?
Yes. +initialize is not call until you try to use your class. So there is no garantee it will be call at all, and even if it is called, nothing prevent creation of instance of the super class before it append. Le 11 mars 2012 à 08:05, Antonio Nunes a écrit : > In the latest public release of my software, I used method swizzling to force > creation of my subclass when the system tries to create instances of its > superclass. However, I have received a very few reports where apparently > instances of the superclass are still created, and wreak havoc (i.e. they > cause a crash). In what way is it still possible for instances of the > superclass to be created? > > The swizzling is performed early on during the application startup: > > + (void)initialize > { > // To force PDFDocuments to be created as NMD_PDFDocuments > // Necessary because of an issue with PDFThumbnailView > Method originalMethod = class_getClassMethod([PDFDocument class], > @selector(allocWithZone:)); > Method superMethod = > class_getClassMethod(class_getSuperclass([PDFDocument class]), > @selector(allocWithZone:)); > > Method replacedMethod = class_getClassMethod([PDFDocument class], > @selector(allocWithZoneReplacement:)); > if (superMethod == originalMethod) { > class_addMethod(object_getClass([PDFDocument class]), > @selector(allocWithZone:), > > method_getImplementation(replacedMethod), > > method_getDescription(replacedMethod)->types); > } > > // To force PDFPages to be created as NMD_PDFPage > originalMethod = class_getClassMethod([PDFPage class], > @selector(allocWithZone:)); > superMethod = class_getClassMethod(class_getSuperclass([PDFPage > class]), @selector(allocWithZone:)); > > replacedMethod = class_getClassMethod([PDFPage class], > @selector(allocWithZoneReplacement:)); > if (superMethod == originalMethod) { > class_addMethod(object_getClass([PDFPage class]), > @selector(allocWithZone:), > > method_getImplementation(replacedMethod), > > method_getDescription(replacedMethod)->types); > } > } > > > The replacement method lives in a category on PDFPage: > > @implementation PDFPage (PDFPage_AllocWithZoneReplacement) > > // Forces PDFPages to be created as NMD_PDFPages > + (id)allocWithZoneReplacement:(NSZone *)zone > { > if ([self class] == [PDFPage class]) { > return [NMD_PDFPage allocWithZoneReplacement:zone]; > } else { > return [super allocWithZone:zone]; > } > } > > @end > > > The only change I can think of that might make a difference is to change: > if ([self class] == [PDFPage class]) > to > if ([self class] != [NMD_PDFPage class]) > > but why would this code ever be called for any classes other than either > PDFPage or NMD_PDFPage? Maybe someone can point out circumstances under which > this whole setup can fail, or be sidestepped. > > -António > > > A merry heart does good like medicine > > > > > ___ > > Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) > > Please do not post admin requests or moderator comments to the list. > Contact the moderators at cocoa-dev-admins(at)lists.apple.com > > Help/Unsubscribe/Update your Subscription: > https://lists.apple.com/mailman/options/cocoa-dev/devlists%40shadowlab.org > > This email sent to devli...@shadowlab.org -- Jean-Daniel ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Forcing subclass creation through method swizzling not airtight?
On 11 Mar 2012, at 09:48, Jean-Daniel Dupas wrote: > +initialize is not call until you try to use your class. > So there is no garantee it will be call at all, Thanks Jean-Daniel, I think I can be pretty confident it is called, since this initialize is in my NSApplication subclass. Should be called before anything is done that involves PDF documents and pages. (By the way, now that I noticed the safeguard was missing, I adjusted the method to: + (void)initialize { if ( self == [NMD_Application class] ) { ... } } > and even if it is called, nothing prevent creation of instance of the super > class before it append. Do you mean before the swizzling occurs? Knowing my code that would be unlikely. The only place where I don't control directly what type of page gets created is in the PDFThumbnailView when a user drags a PDF document in from the Finder, and that can only happen after the app has finished starting up and opened a document. But maybe you mean something else by "before it append"? -António There is nothing as strong as real gentleness, and there is nothing as gentle as real strength. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: ivar access during -finalize
On 11 Mar 2012, at 08:01, Quincey Morris wrote: > On Mar 10, 2012, at 23:18 , Eric Wing wrote: > >> I don't disagree that finalizers are hard and need to be approached >> with great care. And I agree that all 4 of your points are valid. >> However, I think this description of the retain cycle problem might be >> a little over-dramatic. Retain cycles have always been a problem in >> classic memory management and are still a problem even under ARC. Yet >> there is over a decade's worth of code that managed to write code to >> the Cocoa framework and for the most part avoid retain cycles. With a >> simple scoped problem, well defined strategy, and some care, I think >> this is entirely doable. And if he were to go manual management or >> ARC, he has to avoid retain cycles anyway so he still has to design >> carefully. > > I think I'd put it this way: > > There's a difference between a retain cycle in a retain/release (RR) app and > a retain cycle introduced into a GC app by using CFRetain. > > In the first case, the app is architected so that cycles are manually broken > in cases where that's necessary. > > In the second case, the app was previously architected to *ignore* any > question of cycles, since normally they're irrelevant to GC. By using > CFRetain, the question is no longer irrelevant, and the app may need to be > re-architected, and the changes may not be local to the places where CFRetain > is explicitly used. On top of that, in a GC app, you aren't in control of all > of the code (you're using Cocoa frameworks, other frameworks and libraries, > whose internal use of references is unknown and unmanageable). > > At risk of making another sweeping generalization, I'd say that spending your > time on doing complicated things with finalization is a terrible waste of > resources. > > The finalization/resource-disposal problem is the *big* drawback to GC apps. > Retain cycles are the *big* drawback to ARC apps. Both of them require > considerable design and implementation effort to solve. In Jonathan's case, > using CGRetain would mean he has to solve *both* at the same time. If he > can't solve the finalization problem more directly, he'd probably be better > off re-architecting the app for ARC and just dealing with the cycles**. > > But, as I noted before, he could be lucky in using your suggestion. It might > be two small problems instead of two big problems. :) I think both Eric an Quincey are making valid points. Unrestrained use of CFRetain/CFRelease in a GC app could certainly lead to trouble. It could also be used with restraint, what is probably what Eric had in mind. The category disposal counting solution that I proposed certainly works. It has some advantages: 1. Resource disposal isn't tied to the object lifetime so disposal is predictable. 2. It doesn't require any code in -finalize. The downsides are: 1. What is essential (in my case) an internal class resource management problem leaks out into the application space as I have to explicity manage the disposal count. 2. A failure to balance the disposal retain/release calls will leak data in temporary files - which may be a big deal depending on the content. My conclusion: 1. The CFRetain/CFRelease solution is elegant and will I think suffice for my admittedly simple scenario. 2. Under GC CFRetain/CFRelease use the GC ref counting mechanism so we are still working with the central GC memory management system. 3. I will be applying the retain/release to ivars which *should* never reference self so retain cycles should not be a problem. I agree with Quincey though that a complicated -finalize method is probably a bad -finalize method. Regards Jonathan Mitchell Mugginsoft LLP ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Forcing subclass creation through method swizzling not airtight?
Le 11 mars 2012 à 13:28, Antonio Nunes a écrit : > On 11 Mar 2012, at 09:48, Jean-Daniel Dupas wrote: > >> +initialize is not call until you try to use your class. >> So there is no garantee it will be call at all, > > Thanks Jean-Daniel, > > I think I can be pretty confident it is called, since this initialize is in > my NSApplication subclass. Should be called before anything is done that > involves PDF documents and pages. > > (By the way, now that I noticed the safeguard was missing, I adjusted the > method to: > > + (void)initialize > { > if ( self == [NMD_Application class] ) { > ... > } > } > >> and even if it is called, nothing prevent creation of instance of the super >> class before it append. > > Do you mean before the swizzling occurs? Knowing my code that would be > unlikely. The only place where I don't control directly what type of page > gets created is in the PDFThumbnailView when a user drags a PDF document in > from the Finder, and that can only happen after the app has finished starting > up and opened a document. But maybe you mean something else by "before it > append"? > No. If you make sure the class is initialize before anything else append (especially before opening any document), and if the safe guard does not fix you issue, I don't see why it shouldn't work. That said, I don't know either how PDFPage instances are created. It is perfectly valid for a PDFDocument to explicitly create subclass of PDFPage if it want to. In such case, your alloc method will never return a NMD_PDFPage instance. I don't think it has anything to do with you issue, but in your replacement method, you can simply use (self == [PDFPage class]) instead of [self class], as you are in a class method, and self represent the class itself already. -- Jean-Daniel ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Transition from [NSEvent phase] to [NSEvent momentumPhase]
Hello, in a custom view I'm processing -scrollWheel: events for smooth scrolling using the trackpad. When the user flicks across the trackpad, scrolling events first go through a phase cycle delivered through [NSEvent phase] (NSEventPhaseBegan -> NSEventPhaseChanged -> NSEventPhaseEnded). After that (depending on how the flick ended physically), the system may deliver additional scrolling events with [NSEvent momentumPhase] set (NSEventPhaseBegan -> NSEventPhaseChanged -> NSEventPhaseEnded). A typical sequence of events looks like: phase: NSEventPhaseBegan / momentumPhase: NSEventPhaseNone phase: NSEventPhaseChanged / momentumPhase: NSEventPhaseNone [...] phase: NSEventPhaseChanged / momentumPhase: NSEventPhaseNone phase: NSEventPhaseEnded / momentumPhase: NSEventPhaseNone phase: NSEventPhaseNone / momentumPhase: NSEventPhaseBegan phase: NSEventPhaseNone / momentumPhase: NSEventPhaseChanged [...] phase: NSEventPhaseNone / momentumPhase: NSEventPhaseChanged phase: NSEventPhaseNone / momentumPhase: NSEventPhaseEnded The trouble is that there seems no way of knowing that there will be momentumPhase events following a "normal" phase cycle. I need to do cleanup but I must be sure scrolling is over before doing it. The system knows (at the time of sending the final normal -phase event) that it's going to send additional -momentumPhase events. Is there a way to find out? Regards Markus -- __ Markus Spoettl ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com