WatchKit without ARC causes crash when dealloc - automatic-ref-counting

The watch app I am developing is not using ARC. And so I releases all the properties of objects in each interface in dealloc as below.
-(void)dealloc {
[obj1 release];
[obj2 release];
...
[super dealloc];
}
This causes crash when i close the interface (for example to go back to main interface). Why is this so?

Retains and releases need to be balanced in the context of your class. Probably you didn't retain when you assigned to one of those instance variables, and thus it's an over-release. You can try enabling zombies to catch the message to a deallocated instance if that's the case.

Related

Autofac SingleInstance() and Xamarin Forms

To start, let me say that I have read several questions here about SingleInstance, but still cannot find a direct answer that helps me. That said, I apologize if I missed anything.
Here's my question:
I am building a Xamarin Forms app for iOS and Android. I have a single AppInitializer class in a PCL where I register all of my interface dependencies using Autofac. I then assign the Container from the builder as a static property on the app class. The problem I encounter is that while I'm registering everything with .SingleInstance(), I'm not actually getting a single instance.
Init Logic Example:
var builder = new ContainerBuilder();
builder.RegisterType<ErrorHandler>().SingleInstance().As<IErrorHandler>();
…
builder.RegisterType<MemberViewModel>().SingleInstance().As<IMemberViewModel>();
…
AppContainer.Current = builder.Build();
I am letting Autofac handle resolving interfaces in my constructors. For example:
public MemberViewModel(ISettingsViewModel settings, IErrorHandler errorHandler, …) : base(settings, errorHandler){…}
I then use said model on a page as below:
Example page usage:
public ProfilePage()
{
InitializeComponent();
var displayModel = Model.CurrentMember;
…
}
…
**public IMemberViewModel Model =>
AppContainer.Current.Resolve<IMemberViewModel>();**
In this example I set Model.CurrentMember's properties immediately before arriving on this page. I've set breakpoints and know for a fact this is happening. However, when I resolve the instance of the model, the properties on CurrentMember are null.
Am I doing something wrong here or have I encountered a bug?
-Edit-
Made it clear that I'm using Autofac.
-Edit 2-
Adding more detail.
My implementation of the IMemberViewModel class has various properties on it, including an observable object called current member. It is declared as below:
public class MemberViewModel : ViewModelBase, IMemberViewModel
{
…
(see constructor above)
…
public MemberDisplay CurrentMember =>
m_CurrentMember ?? (m_CurrentMember = new MemberDisplay())
On the implementation of IMemberViewModel I have a method that sets the various properties on CurrentMember.
The order of operations is this:
The end user taps an image for a member. This fires a command on the (theoretically) singleton instance of the IMemberViewModel implementation. This command executes an async task that awaits an async call to the API to load the data for that member. After that data is loaded and the properties set on CurrentMember, the app navigates to the profile screen. The profile screen resolves IMemberViewModel (per above).
Expected Behavior:
The properties on CurrentMember from the resolved instance of IMemberViewModel are set to the values that have just been set from the load data method. This expectation arises from assuming that there is a single instance of IMemberViewModel.
Actual Behavior:
The CurrentMember's properties are at their default values, i.e. string.Empty, 0, null, etc.
The odd thing here is that this doesn't happen to every model. I have a message model that I am resolving in the same manner on the same screen and it seems to be fine.
This issue turned out to be caused by the way we were going about initializing everything. For posterity's sake, I will give a brief breakdown of what was happening and what I did to prevent it.
Previous App Flow:
App opens & constructor is called. This calls into the initialization routine above.
User logs in.
First instance of IMemberViewModel resolved using static container.
A message pops up asking the user for Push Notifications Permissions
When this happens, the app OnSleep is called (iOS)
After the user selects an answer, OnResume is called.
OnResume calls initialization routine
New container created.
Call to load data happens on old container, new pages reference new container.
Issue arises as described above.
Correction to the flow:
First, from what I can tell the init calls do not need to be made on resume and/or start if made in the app constructor. If the app is "killed" because other apps need the memory space, a fresh version of the app will be created on next launch (see the Android Activity Lifecycle and the iOS App Lifecycle).
Second, because I'm paranoid and because it can't hurt, in the app init routine I am now checking to determine whether the container exists and whether the interface is already registered.
public static void Init(ISetup setup)
{
if (Container != null && IsModelRegistered()) return;
RegisterDependencies(setup);
…
}
private static bool IsModelRegistered()
{
return Container.IsRegistered<IMemberViewModel>();
}

UIImagePickerController takePicture crashes

I have been trying to find out what is causing this crash.
My main view controller has some code like this to start camera picker.
pickerControl = [[UIImagePickerController alloc] init];
pickerControl.sourceType = UIImagePickerControllerSourceTypeCamera;
pickerControl.allowsEditing = NO;
pickerControl.wantsFullScreenLayout = YES;
pickerControl.showsCameraControls = NO;
pickerControl.cameraOverlayView = overlay;
pickerControl.delegate = self;
overlay.delegate = self;
[self presentViewController:pickerControl animated:NO completion:nil];
The overlay is a view with a few buttons at the bottom. one of them is calling back to take picture.. and the call back will call takePicture like below..
[pickerControl takePicture];
I dont know what is causing it, but it crashes immediately after calling takePicture. It doesn't happen all the time.. but it crashes more often.
Please help to understand what is going wrong.
You're asking about beta software that's accessible only after consenting to a non-disclosure agreement. So I'm going to ignore the iOS 7 aspect of the question.
As to getting a crash log, if you already know which method call is crashing then you're not going to get much out of it. But what you can do is use C's signal to install exception handlers for the various exceptions you want to trace.
Upon receiving such an exception, use [NSThread callStackSymbols] to get an array of call stack symbols — a backtrace in effect. You can then hastily write that to disk and, next run, read it back and notify yourself of it accordingly. Services like Crashlytics accumulate them and post them to a server. You could just open an MFMailComposer and send them to yourself as an attachment.
Using the Crashlytics SDK or a similar product directly would allow you to get live, traced crash reports regardless of whether the build has yet been submitted to Apple and without requiring Xcode to do any parsing.

Trouble passing a pointer between child ViewControllers in iOS6

My problem is with an iOS 6 tabbed application. My work-in-progress has 5 tabs and several tabs are gateways to other view controllers. Most pages need access to a Model object, which contains data stored as arrays, strings, and so on. A bare-bones model is populated at runtime and the user can add to it throughout the application lifespan. For example, the code listed below is from my AppDelegate file , where it is passing a pointer to the bare-bones Model to the Project View Controller. This works fine: the tab application uses the navigation controller array stack; because I know the Project page is at index 2, I can send the model to it.
My problem has to do with the sub views of the Project page. For example, as a sub view to the Project page there is (or should be) a File_IO page where the user handles file operations. The File_IO page also needs access to the Model object. But when I try to send the Model pointer from the Project page to the File_IO page, the technique I used previously (from the AppDelegate to the Project) does not work. I point to an empty Model in the FileIO ViewController.
Example code: this is in the AppDelegate, and it works fine: the bare-bones Model in the Project ViewController is populated with the data.
//To the Project View Controller...
UINavigationController *project_NavigationController =
[[tabBarController viewControllers] objectAtIndex:2];
Project_ViewController *project_ViewController =
[[project_NavigationController viewControllers] objectAtIndex:0];
//This hides the navigation bar on the project page but it also removes the bar on any subsequent pages! They need to be programmmatically reset in ViewDidLoad.
[project_NavigationController setNavigationBarHidden:YES animated:YES];
project_ViewController.currentGeoModel = newGeoModel;
Now, my Project_ViewController is embedded in a NavigationController and has 4 child ViweControllers. One is named FileIO_ViewController. I want to pass the currentModel from the Project_ViewController to the FileIO_ViewController. Under the - (void)viewDidLoad method I have tried a number of things, which do not work. For example,
UINavigationController *project_NavigationController = (UINavigationController *) self.presentedViewController;
FileIO_ViewController *fileIO_ViewController = [[project_NavigationController viewControllers] objectAtIndex:1];
fileIO_ViewController.currentModel = currentModel;
compiles but when I try to access currentModel inside the FileIO_ViewController methods, it is empty.
If anyone can take the time to help I would be very appreciative. The best answer for me would be in the form of an explicit code example showing how to pass the pointer to an object like my Model from a ViewController to another ViewController where you do not explicitly know where in the stack the child VC lies. (In my example I used Index 1 but I do not actually know at which Index the FileIO_ViewController lives as I have three other ViewControllers under the Project_ViewController. I've tried several integers with no success.)
If you do answer this, please consider me a New Guy when it comes to iOS 6 and objective C -- climbing Mount Apple has been a long haul and I isn't anywhere near the top yet!
Thanks
Tim Redfield
Norway
If you have a shared single model for your app, you shouldn't proactively pass the pointer around, you should make the model available from a single location and leave it to individual objects to access this same model when they need to. A good location for your model pointer is in your Application delegate.
In the appDelegate's .h file, declare a property for your model:
//appDelegate.h
#property (nonatomic, strong) MyAppModel* appModel;
After you instantiate your model in the appDelegate, just assign it to the property:
//appDelegate.m
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.appModel = [[MyAppModel alloc] init];
//set up bare-bones appModel here
return YES;
}
Then you can access this property from any viewController that needs model data thus:
#import appDelegate.h;
AppDelegate* appDelegate = [UIApplication sharedApplication] delegate;
MyModel* model = appDelegate.model
(Better still, make the model object into it's own Singleton object, but using the appDelegate will get you started)
If you need to pass models around, then you need to take care that you are passing them to the right object. This is where your existing code is breaking. For example you are making many assumptions about the structure of a NavigationController stack. But whenever you move back down a stack by popping a controller off the top, you lose that top controller instance completely. When you 'return' to that controller by going forwards on the stack, in fact a new instance is created (unless you have taken care to keep a pointer hanging around and make sure to push to that pointer). If you need more help on this aspect, you will need to describe exactly the layout of your app, and how you are creating your viewControllers, navigationController stack, etc.
update (following your comments)
If your changes to the model are valid throughout the app, then I don't see why you can't just access the model when you need to from wherever you happen to be in the app via appDelegate.model. If you have concurrent versions of the model, you could look at making a singleton data manager object which could handle the details of storing an array of models (or a model history) and providing the correct model as per request. The principle is the same - rather than proactively passing model objects into your viewControllers, let them request data from a centralised source as they need it.
Regarding your description "Now, my Project_ViewController is embedded in a NavigationController and has 4 child ViewControllers.", I don't think you have quite grasped the distinction between Classes, Storyboard scenes, and instances.
You have this arrangement in a part of your storyboard:
UINavigationController
| push push push
|->UIViewController1 -----> UIViewController2 -----> UIViewController3 ----->
segue segue segue
You talk about passing data directly from VC1 (say) to VC3 by accessing the NavController's stack.
What you need to consider is that the storyboard describes a template showing how instances will interrelate when they are instantiated. They are not instantiated just because the storyboard is loaded. When you have arrived at VC1, the ability to segue to VC2 and VC3 is laid out before you in the template, but neither VC2 nor VC3 - as instances - exist until you initiate the segue. The segue process instantiates it's destinationViewController Therefore it makes no sense to pass data from VC1 directly into VC3. When you are at VC1, the navController's stack only contains one item (a VC1 instance); when you segue to VC2, it then contains instances of VC1 and VC2, and it is only when you actually segue to VC3 that the instance is created and placed in the stack.
Stepping through your code:
UINavigationController *project_NavigationController =
(UINavigationController *) self.presentedViewController;
the presentedViewController property works with modal segues, where you have a presenting, and a presented, view Controller. NavControllers on the other hand work with push segues (as they push child viewControllers onto their viewControllers stack, which is where you can obtain pointers to them from).
In this context, self.presentedViewController is nil, which you are assigning to a new variable. The code does nothing, but the compiler won't complain.
FileIO_ViewController *fileIO_ViewController =
[[project_NavigationController viewControllers] objectAtIndex:1];
project_NavigationControlle is nil, so it's properties are all nil. fileIO_ViewController gets nil.
Likewise in the last line you are sending a message to nil, which is not an error, but faintly redundant.

iOS 6 MKMapView Memory Leak and Crashes app after some time

iOS 6 MKMapView seems to be using the tons of memory, when we starts zooming and playing around with the Map View in our application(for around 7-10 mins), When we come out of the controller which has MKMapView, its some how not releasing the total memory(I am using ARC in my App). I am allocating and initializing the MKMapView thru NIB.
Controller 1 -->Controller 2 (has MKMapView)
1.5MB -->40-60MB (I have used the Instruments to find out leaks, but of no use)
When i come back to Controller1 the live bytes seems to be 7-10MB, after every visit to controller 2 there is around 2-3MB of increment in the Live Bytes, after some time it crashes the application, in console it says "Received Memory Warning". can any one please help? If you need any more info please let me know. Thanks in Advance.
This is because of the way MKMapView works. There's an operation pending, so MapKit is retaining the MKMapView and it hasn't actually been deallocated yet. That isn't itself a problem. The problem is that it's still sending messages to your delegate.
The workaround is simple: As part of your view controller's cleanup set the map view's delegate to nil, which will prevent MKMapView from sending messages to it.
This is documented in MKMapViewDelegate Protocol Reference:
Before releasing an MKMapView object for which you have set a delegate, remember to set that object’s delegate property to nil. One place you can do this is in the dealloc method where you dispose of the map view.
Edit: Give Oscar an upvote as well, just below, who provided the documentation quote here.
Given ARC, I suggest this means you should set your map view's delegate to nil in your view controller's dealloc.
You can do some thing like this which resolves my issue . Change the type of map helps it too.
- (void)applyMapViewMemoryHotFix{
switch (self.mapView.mapView.mapType) {
case MKMapTypeHybrid:
{
self.mapView.mapView.mapType = MKMapTypeStandard;
}
break;
case MKMapTypeStandard:
{
self.mapView.mapView.mapType = MKMapTypeHybrid;
}
break;
default:
break;
}
self.mapView.showsUserLocation = NO;
self.mapView.delegate = nil;
[self.mapView removeFromSuperview];
self.mapView = nil;
}
-(void)viewDidDisappear:(BOOL)animated
{
[self applyMapViewMemoryHotFix];
}

viewDidUnload no longer called in ios6

I just installed the new version of Xcode/ios6. viewDidUnload is now depreciated.
In the apple doc,
viewDidUnload [...] Deprecated in iOS 6.0. Views are no longer purged under low-memory conditions and so this method is never called.
But numbers of apps are using this callback to release their properties, like :
- (void)viewDidUnload {
[super viewDidUnload];
self.recipientButton = nil;
self.connectButton = nil;
self.infoLabel = nil;
}
This was the best practice to release your IBOutlets.
So, first question:
What is going to happen these existing apps in iOS 6? Will they leak ?
and second one:
What is the new recommended way to release an IBOutlet property ? In dealloc method ?
For the first Question:
Your ViewController will receive didReceiveMemoryWarning method callback and you can nil out the view & other components in this method
For Reference Do Check WWDC 2012 video Session on EVOLUTION OF VIEW CONTROLLER, in case you haven't (I Believe they are available only for registered developers, but not sure).
Answer to your second one.
[object release]; in dealloc. No need to assign nil to object before releasing.
I recommend you to use weak property for the IBOutlets like
#property (weak) IBOutlet UILabel * labelText;
That way you don't need to do anything in dealloc. In iOS 6, simply ViewDidUnload won't call, iOS5 or earlier it is just call when memory warning have occur.
and second one: What is the new recommended way to release an IBOutlet
property ? In dealloc method ?
What is the "old" recommended way? You must always release retained instance variables in dealloc; it has always been this way and continues to be this way.
It was just that in viewDidUnload (which is only called for low memory) you could also set your properties to nil.

Resources