How to clear MKMapView cache? - objective-c

I am trying load map region and MKMapView delegate methods are not being called on second or subsequent load. None of the delegate methods viz
- (void)mapViewWillStartLoadingMap:(MKMapView *)mapView;
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView;
- (void)mapViewDidFailLoadingMap:(MKMapView *)mapView withError:(NSError *)error;
are ever called. The Only methods called are
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated;
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
It seems that ios4 is caching mapview tiles images.
I found these lines in MKMapViewDelegate Protocol Reference documentation. Highlighted line is my problem.
This method is called when the map tiles associated with the current request have been loaded. Map tiles are requested when a new visible area is scrolled into view and tiles are not already available. Map tiles may also be requested for portions of the map that are not currently visible. For example, the map view may load tiles immediately surrounding the currently visible area as needed to handle small pans by the user.
I need to perform certain operations after the map is loaded but since none of the above mentioned delegate methods are getting called I am not able to perform desired functionality. Can anyone suggest a fix to either clear the cache or provide an alternative solution for this ? I have already tried using the methods described here and this but I am still not been able to get the code working.

I think you can couple willStartLoadingMap, didFinishLoadingMap and regionDidChange, like this:
in willStartLoadingMap set a loading flag to true;
in didFinishLoadingMap set the loading flag to false and also check if you have a queued call for the method that captures the screen. If so, call it;
in regionDidChange check the loading flag and if it's set to false, call the method that captures the screen. Otherwise, queue it so it's executed when the map finishes loading.
This way you're sure that you capture the screen after the tiles have been loaded.
However, regionDidChange may be called many times, so make sure you grab the screen only when the map view changes significantly (you can compare previous map region/center and current map region/center for this).

I created a new project and connected the delegate to my view controller. The first two methods of the three in question gets called. Since it loads all tiles the error delegate method wasn't called.
I just recently walked into similar problems. I subclassed MKMapView and forget to set the delegate in my custom init methods and in awakeFromNib:. Perhaps that's what causing your problems, too.

Related

Transferring Touch points between classes [Objective-C]

I'm working on an alternate version of a program I already wrote, it's mostly for the sake of understanding a little more.
In x-Code (Objective-C), I have a ViewController that calls out a UIView (GraphicsView) that draws a line from the center to the touch point. This sub-view is smaller than the larger ViewController.
The view controller has a label that outputs the coordinates of the touched point.
So far I was able to get everything working, so that if you touch inside the sub-view you get the line AND the coordinates updated and if you touch outside the sub-view you only get the coordinates updated. I did this using delegates which was a little complicated.
I've been reading some books and I learned about using the extern feature and global variables (which are supposed to be bad practice) and I wanted to try the same app but using global variables.
I declared my externCGPoint in the ViewController.h and imported it on the GraphicsView.m file and in the method touches began I put the definition of myGlobalPoint = touchedpoint; followed by an NSLog that displays the coordinates. So far it works. (However it does not update the coordinates)
However whenever I touch outside the sub-view, into the main view the app crashes with a EXC_BAD_ACCESS message. From what I understand the main View cannot access the global variable if it's declared in another class ?
I've read many there stack overflows about this and I;ve tried it in the methods suggested but I keep getting this error.

NSOutlineView subclass not firing data source drag and drop methods

I'm using the excellent NSOutlineView subclass PXSourceList in one of my applications. I'm trying to implement drag and drop to my PXSourceList instance. I have:
connected both delegate and data source outlets in IB to my controller
in awakeFromNib in the controller, set self as the delegate and data source
in awakeFromNib in the controller, registered for dragged types
in the controller, implemented the requisite writeItems: validateDrop: acceptDrop: and
namesOfPromisedFilesDroppedAtDestination: methods and declared them in the controller's .h file
For some reason, the drag and drop methods implemented in (4) are not firing at all. I've tried:
Placing log statements in the drag and drop data source methods - they never get called.
Putting a log statement in one of the other data source method that logs the registeredDraggedTypes of the PXSourceList instance - it always returns the proper drag types assigned in awakeFromNib.
Taking the PXSourceList view instance and unembedding it from all containing views except the NSWindow instance - no luck there either.
Copy-pasting data source code from my application to the sample app that comes with PXSourceList - it all works without modification.
Copy-pasting the working code from the example application into the SK source - it doesn't work.
So essentially I'm in a spot where all data source methods get called except the drag-and-drop methods. It's behaving like I haven't registered for dragged types, but 1) I know I have and 2) the instance responds that it is registered for the dragged types that I set.
Any ideas?
Unfortunately, this is a side-effect of how PXSourceList is implemented; if you look inside PXSourceList.m, it makes itself the delegate and data source of itself (since it inherits from NSOutlineView), implements all of the outline view delegate and data source methods, and when each of these is called, it invokes the implementation of the actual delegate and data source which is being used by PXSourceList with the PXSourceListDelegate and PXSourceListDataSource methods. The reasoning behind this when I built PXSourceList was to have a consistent API rather than mixing and matching NSOutlineViewDelegate/DataSource methods with PXSourceListDelegate/DataSource's additional methods (for badges and icons etc).
The 10.7 SDK (which I assume you're using) added some extra drag and drop methods to NSOutlineViewDataSource. Of relevance here in particular, NSOutlineViewDataSource got the additional method -outlineView:pasteboardWriterForItem: added to it, which is an alternative to -outlineView:writeItems:toPasteboard:.
When you start a drag, NSOutlineView queries the data source (by using -respondsToSelector:) to determine which of these methods it implements and which of these to invoke. Given that PXSourceList implements both, and calls the corresponding -sourceList:... methods on the actual data source, NSOutlineView sees both of these methods as being implemented (even if they're not by your data source), and it seems like NSOutlineView chooses to call -outlineView:pasteboardWriterForItem: if both are implemented. Given that you don't have an implementation of sourceList:pasteboardWriterForItem:, the implementation of -outlineView:pasteboardWriterForItem: returns nil and your other methods don't get called (you can see the code here.)
To cut a long story short...
It looks like for now you'll have to implement -sourceList:pasteboardWriterForItem: instead of -sourceList:writeItems:toPasteboard: (or if you're targeting < 10.7, too, implement both; on 10.6 and below, -sourceList:writeItems:toPasteboard: will be called).
I actually have some improvements to PXSourceList in the works which uses the runtime and should fix problems like these, so keep an eye on the project on GitHub!

Quickly adding multiple items to an UICollectionView fails

I've got this UICollectionView set up with a fetched results controller, using core data. I use UIImagePickerController to add items to the UICollectionView. Now when I tap one of the photos stored on my device, it will be added to my managed object context and will be inserted into the UICollectionView.
Now when I quickly add multiple items, the app crashes with the following error:
2012-10-07 13:17:46.770 PhotoLibrary[2444:907] *** Assertion failure in -[UICollectionView _endItemAnimations], /SourceCache/UIKit/UIKit-2372/UICollectionView.m:2801
It seems like it can't handle adding an item while the animation of the previous added item hasn't ended yet. Just happens when you add them really quickly, but some of the users will do that.
Is there a good way to just wait and add the item when the other one is finished? Users should be able to add them "real time", so I can't just run all the changes at once.
The error only occurred when adding a few items quickly. But the real problem wasn't really related to the animation. I was creating the managed objects used to store the new items in a block, used in the ALAssetsLibrary's assetForURL:resultBlock: method.
Took a while to figure out that that was the problem, the managed objects were created in a separate thread. Turns out that managed objects doesn't handle that well.
Now moved the creation of the new items outside of the block, now it just works fine.
Without example code, I'm presuming the problem occurs when calling the - (void)reloadData method after inserting data into the UICollectionView. The documentation for this method explicitly calls out the fact you shouldn't call this method in the middle of an animation caused by insertion/deletion since the insertion/deletion will invoke the animation code automatically.
Some other notable methods are - (void)insertItemsAtIndexPath:(NSArray *)indexPaths and - (void)performBatchUpdates:(void (^)(void))updates completion:(void (^)(BOOL finished))completion. I have not used the batch method, but I've used the insert method a number of times and it works well.

Registering all view controllers for NSNotifications

I have a custom graphic that is to be displayed to a user when an event occurs. The graphic needs to be displayed on whichever viewController is currently being displayed to the user.
The way i have programmed it so far is by adding to ALL viewcontrtollers:
1) the .h file for the custom graphic class
2) an observer for the NSNotification event that is raised
3) the method which actually draws the graphic.
This doesnt feel like a very efficient way of doing things and i was wondering if anyone has a better way of doing things?
To me it sounds like you've done it in a fairly sane way. The only other way I can think is to just add the graphic to the window which would then overlay on the current view controller and you'd only need to have one object listening for the notification. You could use the app delegate for instance. But then you would have to worry about rotation of the screen yourself when adding the graphic over the top.
What you are doing is correct .. The only thing you can improve is to mauve the drawing graphics part to the custom graphic class.. (if you are not already doing so...
just Make a UIViewController variable as a member variable to the graphics class..and then set it up to the current view displaying..after you receive the notifications..and the class will itself draw the code based on the ViewController you set it up to
The reason it doesn't feel efficient is that you're duplicating a lot of code. That's more work at the outset, and it creates a maintenance headache. You should be taking advantage of the inheritance that's built into object oriented languages, including Objective-C.
If you want all your view controllers to share some behavior, then implement that behavior in a common superclass. Derive all your other view controllers from that superclass, and they'll all automatically get the desired behavior. Your superclass's initializer can take care of registering the view controller for the notification(s) that you care about, and -dealloc can unregister it. This way, you don't have to clutter up each view controller with the same repeated code, and if you want to change the code you only have to do it in one place.

Change UIView Dynamically

Working on cs193p (stanford online videos of iphone programming), I am working on Presence1 exercise
I am trying to change a UIView which is a subview of another view dynamically.
For those of you who are not aware of the assignment posted on the course, Basically the architecture of the app is as follows:
Nav Controller -> (Root) View Controller - (VC)1 for 1st screen -> calls Detail View controller VC2 for next screen
Now 1st screen has images and text that I want to load dynamically from my model (which is an object I instantiate in App delegate before pushing the 1st VC on navigation stack. I have defined a parameter in initWithNibName method to pass this model object while initializing the nib for VC1. And I also try to set the image from the model over here and in viewDidLoad and viewDidAppear methods. Its not working.
When I debugged, I saw that the model object being passed is empty.
If you understand the problem, please lemme know what am I missing.
I can post the code if required but will have to post the whole thing to make any sense.
Nailed - I was releasing my model object when not required - I was creating a "reference" to one of my objects present in the model (array containing a list of objects) . Note - I was not creating a new object by using alloc/copy. I was then releasing it (even though after the push on to the navigation stack) - Obviously causing my object memory space to get cleared and that reflected in my view controller that was receiving that model object as a parameter in its init method. This was giving the illusion that the object is not getting passed to the view controller!
Lesson Learned earlier - Be very mindful about releasing objects.
Lesson Learned Today - Be very cautious when releasing objects. Don't over release objects - make sure you are releasing an object only if you are calling alloc/copy or retaining it explicitly - memory management 101 - revisited :)
Thanks all for not replying to this question. In a way it forced me to scrutinize my code at a very micro level and I am sure I wont forget this for rest of my life! :)