0

I am debugging an interesting issue with my app.

The app is targeted at iOS6.1 and it is using ARC. Here is some background since it is too large to copy paste into SO.

There is a Dashboard class that has a child view controller. This child view controller is rather large, it has buttons two scroll views that get dynamically created based on the CoreData object that The dashboard controller hands to it. WHen the dash board controller is done with the child controller it destroys it and creates another with a different core data object.

One of the views in the child controller that gets dynamically created and stuffed into a UIScrollView is a subclass of UIWebView. Lets call it SubWeb. When an instance of SubWeb is created it uses an NSOperationBlock to do some file fetching over the network along with some other stuff (write to disk, encryption etc). Once it is done, it needs to be able to insert a file or webpage into the SubWeb instance.

I solved for this by giving SubWeb a strong property. This is my problem: My clean up is never able to destroy the child view controller or the SubViews; I have confirmed this with an instruments allocation study that targets my classes. by by creating and destroying child view controllers (and SubWeb objects) I can watch the memory allocations for both the child view controller and the Sub wWeb objects staircase up until the app crashes. What is weird is that when I set the NSBlockOperation to weak, the destroy routine does what I expect.

I need the strong reference because I only front load a few SubWeb objects with a real file to start, then if user scrolls over to them I lazy load the needed file by pushing the property that

Here is WebView I am referring to when the child view controller and instances of SubWeb view are not cleaned up:

#import <UIKit/UIKit.h>

@interface MySubWebView : UIWebView

@property (strong) NSBlockOperation *fileLoadOperation;

@end

Here is the WebView when it is cleaned up (But - now the lazy Blocak operations are null whenn I need them:

#import <UIKit/UIKit.h>

@interface MySubWebView : UIWebView

@property (weak) NSBlockOperation *fileLoadOperation;

@end

The only difference is the strong and the weak type. Has anyone ever used NSBLockOperation for this type of lazy loading action? Is there a defferent/better way I might use to solve the lazy load?

hippeelee
  • 1,788
  • 1
  • 10
  • 21

1 Answers1

1

I'm not following your logic for making the NSBlockOperation object strong. It should generally be weak. If the operation completes, there's no reason to keep the operation object any more.

In answer to the question on your memory consumption, you're running out of memory because you undoubtedly have a strong reference cycle (a.k.a. retain cycle). If the block has a reference to self (whether explicitly, or implicitly by referencing some of your controller's instance variables), you can end up with a strong reference cycle (i.e. two objects that maintain strong references to each other, and thus neither will ever get deallocated unless you manually clean it up.)

For information about retain cycles see Use Weak References to Avoid Retain Cycles in the Advanced Memory Management Programming Guide. Also see Avoid Strong Reference Cycles when Capturing self in the Programming with Objective-C guide.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • There are some NSBlockOps that fire right away and others that might need to fire later and do a network request for a file to be loaded into view. When the block operation is weak and fired immediately no problem. The four files I want to load by default come in as expected. However, the remaining six weak block operations that were assigned to the sub classed web views property are null, these views are not on screen and so I don't want to fetch the file unless the customer performs an action that indicates they are interested in seeing that content. – hippeelee Jun 22 '13 at 02:35
  • I have already read the first link and will check out the second to see if it has any ideas for how to solve the lazy load on demand use case I am solving for in this situation. What is your suggestion for handling a data structure that has a list of file, some of which need to be fetched via network at creation time and other which may or may not need to be fetched at a time to be determined later? That's really what I am after, I suspect that my current approach could be improved and would like some general advice or war stories that I can explore with the code I am working with. – hippeelee Jun 22 '13 at 02:42
  • @hippee-lee I simply wouldn't create the operation until I need it. For example, when lazy loading of images in a table view, I don't create the operation to retrieve the image until I'm going to add the operation to my queue. – Rob Jun 22 '13 at 02:46
  • Thanks @Rob. That's kind of what I have been mulling over the past hour. I may have to do more refactoring than I want to accomplish that though so I was trying to shoehorn the strong op. The files have to be in a specific order and othe business requirements. My issue is that the first requirement was to load everything at once so it made sense to throw it all onto a queue and let the callback blocks sort themselves out when they were ready to. Now, I'm semi locked into how it did that but the updated requirement is to only load four at first and the others later. Thanks again for the answer. – hippeelee Jun 22 '13 at 03:18
  • @hippee-lee If you're stuck with this approach, it can work, but just make sure you don't have strong references to `self` in the block. See the use of `weakSelf` in that second article in my answer. Also, the "Use Lifetime Qualifiers to Avoid Strong Reference Cycles" subsection of the ["ARC Introduces New Lifetime Qualifiers"](http://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226-CH1-SW4) section shows some more examples (not of `self`, but of the basic idea of preventing retain cycles in blocks). – Rob Jun 22 '13 at 05:05