I've just upgraded my application to ARC, but I am having issues with how it handles classes with delegates. Because I am targeting iOS 4.0 and above, I am using __unsafe_unretained and #property (unsafe_unretained) to store the delegate pointers.
However, what I am now finding is that the services (that include delegates) I create in my view controllers are now hanging around after I have removed that view controller, which result in trying to communicate back with the view controller (delegate) after it has been deallocated... And therefore getting an error with Zombies enabled.
How can I update my code in either the view controller or the service, so that when the view controller is removed (popped off the nav controller stack) the service with the delegate pointer also gets removed from memory?
It turns out that it's not me that's doing anything wrong...
The offending NSZombie turned out to be due to the MKMapViewDelegate, which keeps sending 'mapView:didUpdateUserLocation:' after the View Controller it belongs to gets deallocated. I know.
I resolved it by intercepting the Back button in my View Controller, and set the delegate to nil before popping it:
- (void)backButtonTapped
{
self.mapView.delegate = nil;
[self.navigationController popViewControllerAnimated:YES];
}
I don't know why MapKit holds onto a delegate after it has been dealloc'd. If anyone knows I'd be grateful to find out more.
Related
To be very specific: If I get the managed object context from the app delegate and do not set any parameters on it, what happens when running inserts, updates followed by save()?
Does the app block on save() until done?
Yes, the save method blocks. It's not even a default-- that's how it is, always. Does't matter if the context came from the app delegate or somewhere else, save is a synchronous method.
This what it came down to:
Normally, when I create an object, I only set the main key (properties that don't change through the lifecycle of the object) on creation. I then use an update method to complete the creation. In this particular case, I changed one property on the server from 'creational' property to 'updateable' property, but I missed it in the app. So the app was deleting the objects only to have the server create them again a bit later...
I need to create a Tab view in iOS. I tried to do this by simply adding a UITabBar to an MvxViewController but I could not get that to work (See this question if interested)
I am now trying to go use the approach MVVMCross and Apple seem to push me towards, a TabController.
In our Core project we have 4 ViewModels that are displayed from one or more places using a ShowViewModel call and are initialised with a customerNumber.
CustomerViewModel
CustomerOrdersViewModel
CustomerHistoryViewModel
ReturnsViewModel
In Android and Windows Store we have separate Views for each of these ViewModels. I do not want to change our Core implementation to support iOS. I will create a new ViewModel called TabbedCustomerViewModel and that will have 4 properties, one for each of the hosted ViewModels.
Using a custom MvxTouchViewPresenter registered in the iOS project I can listen for requests to Show one of the Customer views and then switch the Request to TabbedCustomerViewModel. I have that working, the new ViewModel gets created and the initialisation paramaters that would have been passed to the original VM are passed to the intercepting VM's Init method.
The problem I am having is knowing how I should be initialising the hosted VMs. I assume I am going to have to ctor, init and Start them manually. Has anyone got any thoughts on how to do this?
The N-25 Tab Tutorial does not have to worry about this as its hosted VMs are not standalone so don't have Init and Start dependencies
I have the initialisation of the VMs working now too. When the View loads it checks if it is within a Tabbed UI by looking at the ParentViewController.
If it is it calls a custom method on the new TabbedCustomerViewModel. I have copied the code that MVVMCross use and added it to the new Method
try
{
mvxViewModel.CallBundleMethods("Init", this.initialisationParameters);
if (reloadedState != null)
{
mvxViewModel.CallBundleMethods("ReloadState", reloadedState);
}
mvxViewModel.Start();
}
catch (Exception exception)
{
throw exception.MvxWrap("Problem initialising viewModel of type {0}", mvxViewModel.GetType().Name);
}
The initialisationParameters and reloadedState are stored by TabbedCustomerViewModel when it is initialised so that it can pass it down to the ViewModels it is hosting
I would like to ask, What would be the most suitable scope for my upload photo service in Grails ? I created this PhotoService in my Grails 2.3.4 web app, all it does is to get the request.getFile("myfile") and perform the necessary steps to save it on the hard drive whenever a user wants to upload an image. To illustrate what it looks like, I give a skeleton of these classes.
PhotoPageController {
def photoService
def upload(){
...
photoService.upload(request.getFile("myfile"))
...
}
}
PhotoService{
static scope="request"
def upload(def myFile){
...
// I do a bunch of task to save the photo
...
}
}
The code above isn't the exact code, I just wanted to show the flow. But my question is:
Question:
I couldn't find the exact definition of these different grails scopes, they have a one liner explanation but I couldn't figure out if request scope means for every request to the controller one bean is injected, or each time a request comes to upload action of the controller ?
Thoughts:
Basically since many users might upload at the same time, It's not a good idea to use singleton scope, so my options would be prototype or request I guess. So which one of them works well and also which one only gets created when the PhotoService is accessed only ?
I'm trying to minimize the number of services being injected into the application context and stays as long as the web app is alive, basically I want the service instance to die or get garbage collect at some point during the web app life time rather than hanging around in the memory while there is no use for it. I was thinking about making it session scope so when the user's session is terminated the service is cleaned up too, but in some cases a user might not want to upload any photo and the service gets created for no reason.
P.S: If I move the "def photoService" within the upload(), does that make it only get injected when the request to upload is invoked ? I assume that might throw exception because there would be a delay until Spring injects the service and then the ref to def photoService would be n
I figured out that Singleton scope would be fine since I'm not maintaining the state for each request/user. Only if the service is supposed to maintain state, then we can go ahead and use prototype or other suitable scopes. Using prototype is safer if you think the singleton might cause unexpected behavior but that is left to testing.
I am using Mvvmcross crosscore in my project
I am trying to bind my loginviewmodel to the loginviewcontroller
I bound a command for the login button. the app waits until it gets a login response, which is stored in the loginViewModel itself..
How can I communicate this to the loginviewcontroller --- regarding the login status and login error message if any
Can I access the viewmodel datacontext inside my loginviewcontroller ??? and how ?
What is the best approach to communication any items in the viewmodel back ( I basically mean all the NON-UI binding items)
I am using Mvvmcross crosscore in my project
I'm assuming from this that you followed the CrossLight sample N=39.
Can I access the viewmodel datacontext inside my loginviewcontroller ??? and how ?
If you followed N=39. then you can access the DataContext using the property called DataContext - see https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/blob/master/N-39-CrossLight-Touch/CrossLightTouch/MyViewController.cs#L33
public object DataContext
{
get { return BindingContext.DataContext; }
set { BindingContext.DataContext = value; }
}
Beyond this, there are many other examples in the N+1 videos which demonstrate how to communicate between ViewModels and Views including error messages and loading dialogs - e.g. N=34 shows one implementation of progress dialogs - https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/tree/master/N-34-Progress
A complete index of N+1 videos is available on http://mvvmcross.wordpress.com
Obviously not all of these are appropriate for your CrossLight approach to development, but this is where you can allow your custom mvvm approach to fill the gap - it's code for you to write in your custom framework.
One of the best methods solving viewmodel interdependencies is using a loosely coupled approch using the MessageBus/Event Aggregator pattern. There's a plugin for MvvmCross. Or you could use the excellent TinyMessenger.
In principle when using this approach, you no longer establish hard references between the publisher and consumers of arbitrary notifications. Instead notifications get published on a message bus and every one is free to listen and subscribe.
I have created an iPad storyboard application using the newest version of Monotouch. My first screen is a login screen that I only want to show if the user has not saved his credentials. If credentials are available I want to instead navigate to the UITabBarController that is the second scene. I can't seem to find any documentation on how to do this. I tried creating an instance of the UITabBarController and pushing to it but it does not work.
homeScreen = new HomeTabBarNavigator(this.Handle);
this.NavigationController.PushViewController(homeScreen,true);
HomeTabBarNavigator is a UITabBarController that is already linked to other scenes. I get the following error:
[ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object
I assume I am getting this error because I have not defined any views to the ViewControllers property of my HomeTabBarNavigator. I was hoping that those views were already defined but that does not seem to be the case. Any ideas.
The best solution I could find is to call PerformSegue on the controller. Here is some example code:
this.PerformSegue("LoginSegue",this);
The controller that is loaded is the LoginController, and LoginSegue is a Segue that points to the HomeTabBarNavigator. While it is not perfect, the applications loaded the tabbar properly.
I used this stackoverlflow iOS question as the basis for my solution.