Memory management problem (release UIVIewCotroller) - ios

I develop the game for iPad (composing image from puzzles). In my menu i choose level difficult (simple, medium or hard). After selecting the main playing field will be shown.
Here's place, where i create the main playing field:
- (void)simpleDiffButtonClicked:(id)sender
{
UIButton *button = sender;
if (simpleDiffButton == button) {
UIView *mySuperView = self.view.superview;
mainGame = [[MainGame alloc] initWithMode:1 andImage:nil]; //mainGame variable is declared in header file like: MainGame *mainGame;
mainGame.view.frame = CGRectMake(0, 0, 1024, 768);
[mySuperView addSubview: mainGame.view];
}
}
After this playing field is appears (there are a lot of sublayers adding to self.view.layer) and i can interact with it. When i want to quit from it, i click button "back". (here i want to release my viewcontroller)
- (void)backToMenuButtonClicked:(id)sender
{
UIButton *button = sender;
if (nextImageClick == YES) {
return;
}
if (backToMenuButton == button) {
self.view.layer.sublayers = nil; //here's an exception
[self.view removeFromSuperview];
}
}
After clicking "back" button everything is ok. And i can choose difficultly level again. A choose a level, and after it clicking "back" button again and at this place application crashes (EXC_BAD_ACCESS).
As i understand "self.view.layer.sublayers = nil" causes the exception.
Without it everything is ok. But memory is leaking. And after several minutes of playing app was crashes (memory warning 2).
I cannot solve the problem for about a week. I don't understand what to do to release my viewcontroller (or i need to release all sublayers in controller?).
Please, someone help me.
Thanks in advance.

Try to turn on NSZombieEnabled and check out Debugger and Console when it crush, it can give some more info about the problem.
P.S. NSZombieEnabled : http://www.cocoadev.com/index.pl?NSZombieEnabled (you may want to try useing .gdbinit).
P.P.S:
Btw, there might be some other problem in the line where "mainGame = [[MainGame alloc] initW...". -- where [mainGame release] is called? (it should be called as many as simpleDiffButtonClicked which allocs new instance of MainGame to mainGame variable (every time))

Related

ViewController's UILayoutAnchor messed up when added to UINavigationController

I'm playing around with UILayoutAnchor and it works perfectly with my ViewController. But when I add the ViewController to a NavigationController, I didn't get the result I'm expecting. Here's the code:
UIButton *topContainer = [UIButton buttonWithType:UIButtonTypeCustom];
[topContainer setBackgroundColor:[UIColor redColor]];
[self.view addSubview:topContainer];
//Setup anchor
topContainer.translatesAutoresizingMaskIntoConstraints = false;
[topContainer.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = true;
[topContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = true;
[topContainer.heightAnchor constraintEqualToConstant:40].active = true;
[topContainer.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor constant:0].active = true;
the result of the above code:
Now when I make the same ViewController as a root of NavigationController (via storyboard where I also hide intentionally) the same code gives the below result.
The first I've noticed is the background that went from gray to black. The interaction on the viewcontroller also is not working anymore. I've check the inspector of the navigationcontroller and its "user interaction enabled" is checked. And the topContainer(redbar) didn't extend to the edge of the screen.
I've tried using the viewcontrollers readableContentGuide but it extends all the way to the edge. See below code along with the result.
[topContainer.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = true;
[topContainer.leadingAnchor constraintEqualToAnchor:self.view.readableContentGuide.leadingAnchor].active = true;
I also tried showing the NavigationController and a clean build but it still gives the same result. Where did I messed up?
Teddy bear programming really works. The problem is somewhere in my code there is this line.
self.view.translatesAutoresizingMaskIntoConstraints = false;
I got the result I want by just commenting/removing it out. I'm leaving this here just in case someone encounter it.

how do i use if buttons to trigger if statements in xcode?

So i am creating a tic tac toe game (user vs computer) and i want to have -(IBAction) statements with if statements thats would say if(buttonIsPressed), do ____. I cant just say
-(IBAction)button:(id)selector;{
//stuff i want
}
because the buttons are pressed in different order and the computer would have different responses (i want there to be an order). For example, this is what i tried,
-(IBAction)move2;{
if (buttona2){
c2.image = [UIImage imageNamed:#"imgres-3.jpg"];
}
it didnt work because the the result of this if statement ( c2.image = [UIImage imageNamed:#"imgres-3.jpg"];) would start automatically and not run depending on the pressing of the button (it runs right away). Pretty much i want the if statement to run on press of a button (or not work if the button is not pressed.
Can anyone help?
If I understand your question right, you want to check if a button is toggled on or off before running the if statement right? In that case, I would declare a BOOL in your header file
#property BOOL toggle;
Then in your implementation file when the user presses the button the target of the button should have the code:
if(self.toggle == TRUE){
self.toggle = FALSE;
//and any visual UI change you want to show that the button is now off
}else{
self.toggle = TRUE;
//and any visual change you want to show that the button is now on
}
Then in your -(IBAction) your code becomes:
-(IBAction)move2;{
if (self.toggle){
c2.image = [UIImage imageNamed:#"imgres-3.jpg"];
}
}
And that should work.

Strange appearance of the status bar after upgrading to ECSlidingViewController 2

It seems that one particular aspect of iOS programming is to diagnose these weird, seemingly trivial yet frustratingly obscure small problems.
So today, I was happily woking on my recent iOS project, and I decided to upgrade my project to the latest version ECSlidingViewController, what harm could it do right? Just update a few deprecated methods that's all.
So I did all of that. Everything works fine, beautiful. However, I noticed that the status bar is behaving strangely! It is not appearing when I display one of my underLeftViewController, and it is in a weird shade when I push segue that particular underLeftViewController into one of its subsequent VC. What?? How could this be happening? Anyway, a picture is worth a thousand words:
So here is it acting nice and normal:
Now it disappears!!!:
Now it has a weird shade!!!:
And here is a picture of the app with the sliding view controller slided out:
I must have done something crazy to my status bar somewhere, then I thought.
So I looked into my implementation file for the VC where statusbar is acting crazy. It is in fact a subclass of UINavigationController, and its viewDidLoad is empty except with the [super viewDidLoad] line. So nothing suspicious here.
The run test page is in fact the rootViewController for the navVC, so I looked into it. I put all of my view setup code in its viewDidLoad, and this is what it looks like:
- (void)viewDidLoad
{
[super viewDidLoad];
// remove advanced button
self.navigationItem.rightBarButtonItem = nil;
self.navigationController.view.layer.shadowOffset = CGSizeMake(1, 0);
// setupGaugeView
[self setupGauge];
// add run test button
[self setupRunTestButton];
// setup notification container
CGRect notificationContainerFrame;
if ([WRGlobalHelper currentDeviceVersion] >= 7) {
CGFloat statusBarHeight = [WRGlobalHelper statusBarHeight];
notificationContainerFrame = CGRectMake(0, [[self.navigationController navigationBar] bounds].size.height+statusBarHeight, self.view.bounds.size.width, 1);
for (UIView *subview in self.view.subviews) {
CGRect newFrame = subview.frame;
newFrame.origin.y += [WRGlobalHelper statusBarHeight];
subview.frame = newFrame;
}
} else {
notificationContainerFrame = CGRectMake(0, [[self.navigationController navigationBar] bounds].size.height, self.view.bounds.size.width, 1);
}
self.notificationContainerView = [[UIView alloc] initWithFrame:notificationContainerFrame];
self.notificationContainerView.clipsToBounds = NO;
self.notificationContainerView.layer.backgroundColor = [UIColor clearColor].CGColor;
[self.view addSubview:self.notificationContainerView];
// some other unrelated stuff omitted....
}
And the `viewDidLoad's for the VCs where the status bar is acting normal or bizarre but with shade is all quite plain as well, they look like
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
}
Mind blown and I give up at this point. I've spent nearly 2 hours on this single issue already, and my brain hurts at the thought of the disappearing status bar. The almighty and omniscient SO, please help me! Thank you very much!
The status bar is not disappering, the text is just changing its color based on its assigned Style.
This answer will help

Back-like arrow on iOS 7

I need to add a left bar button item in my app that looks like system back button, but is not the system back button, since it will appear on view controller that is the only vc of my navController's stack and execute my own code. Simply writing "Back" isn't really good for me, as I need to display the "<" arrow as well. Is there a way to programmatically create an arrow like that, without making image with that arrow?
You can use any Unicode character (anywhere in your code) for this.
You can find what you want here:
Xcode > Edit > Special Characters...
Search for arrow or back or browse the categories.
Then copy paste the character where required (in the XIB object's title or in the setTitle or setText methods like any other character)
something like:
Try this:
// After you create and place your backButton:
UILabel* arrowLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 10, 20, 20)];
arrowLabel.text = #"<";
arrowLabel.textColor = [backButton titleColorForState:UIControlStateNormal];
arrowLabel.transform = CGAffineTransformMakeScale(1,2);
[backButton addSubview:arrowLabel];
If addSubview gives you trouble, try
[backButton insertSubview:arrowLabel atIndex:0];
Consider using a dummy UIViewController as a root view controller for your UINavigationController’s stack:
[[UINavigationController alloc] initWithRootViewController:[UIViewController new]];
[navController pushViewController:viewController animated:NO];
Then you can use my BackButtonHandler extension to handle back button action (as described in this thread) :
-(BOOL) navigationShouldPopOnBackButton {
[self dismissModalViewControllerAnimated:YES];
return NO;
}
Look at the UIBarButtonSystemItem enum under contants in the UIBarButtonItem documentation:
https://developer.apple.com/library/IOs/documentation/UIKit/Reference/UIBarButtonItem_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40007519-CH3-SW2
These are all of the button styles provided by Apple:
typedef enum {
UIBarButtonSystemItemDone,
UIBarButtonSystemItemCancel,
UIBarButtonSystemItemEdit,
UIBarButtonSystemItemSave,
UIBarButtonSystemItemAdd,
UIBarButtonSystemItemFlexibleSpace,
UIBarButtonSystemItemFixedSpace,
UIBarButtonSystemItemCompose,
UIBarButtonSystemItemReply,
UIBarButtonSystemItemAction,
UIBarButtonSystemItemOrganize,
UIBarButtonSystemItemBookmarks,
UIBarButtonSystemItemSearch,
UIBarButtonSystemItemRefresh,
UIBarButtonSystemItemStop,
UIBarButtonSystemItemCamera,
UIBarButtonSystemItemTrash,
UIBarButtonSystemItemPlay,
UIBarButtonSystemItemPause,
UIBarButtonSystemItemRewind,
UIBarButtonSystemItemFastForward,
UIBarButtonSystemItemUndo, // iOS 3.0 and later
UIBarButtonSystemItemRedo, // iOS 3.0 and later
UIBarButtonSystemItemPageCurl, // iOS 4.0 and later
} UIBarButtonSystemItem;
Perhaps rewind or undo would be close enough for you.

Stuck with UIActionSheetPicker , iOS

This is going to be a very targeted question , as its for people that have actually used the UIActionSheetPicker before.
I used it in my iphone applications and everything worked great , but now that i tried to implement it on my ipad i experienced some problems.
The main problem is that on ipad the picker appears as a "bubble" or "info window" if you prefer , which points at the spot where it was called , like a button a text field etc.
Below is an example of it :
You can see that the "info window" is pointing at the animals button.
In my application i have 4 different buttons. 2 are in the top side of the screen and 2 at the bottom.
Those who are at the bottom , call the picker very well and the picker appears on top of the buttons pointing down on them.
However , the ones on the top of the screen (almost like the one in the image) when they call the picker the picker appears much lower on the screen and doesnt point at them as it should ...
I mean i expected to appear just under the buttons pointing at them (like in the image), but they are almost in the center of the screen pointing nowhere..
Any ideas? Has someone experienced this before?
EDIT
In the beginning , i was calling the ActionSheetPicker inside the buttons action like this:
- (IBAction)selectTopic:(UIControl *)sender {
[ActionSheetStringPicker showPickerWithTitle:NSLocalizedString(#"CHOOSE_TOPIC", nil) rows:self.topics initialSelection:self.selectedIndex target:self successAction:#selector(topicWasSelected:element:) cancelAction:#selector(actionPickerCancelled:) origin:sender];
//when user picks a new topic we clean the titleField to make sure selected title of previous topic doesnt mix up with new topic
titleField.text = #"";
}
Now i am trying to call it like this:
- (IBAction)selectTopic:(UIControl *)sender {
ActionSheetStringPicker *thePicker = [[ActionSheetStringPicker alloc] initWithTitle:NSLocalizedString(#"CHOOSE_TOPIC", nil) rows:self.topics initialSelection:self.selectedIndex target:self successAction:#selector(topicWasSelected:element:) cancelAction:#selector(actionPickerCancelled:) origin:sender];
thePicker.presentFromRect = topicField.frame;
[thePicker showActionSheetPicker];
//when user picks a new topic we clean the titleField to make sure selected title of previous topic doesnt mix up with new topic
titleField.text = #"";
}
Where topicField is my TextField.
Sadly the result is the same. Even now that i am specifying where i want the arrow to point , the picker is called 300 pixels down.
The strange thing is though that even with another other button that is a bit lower than the previous the picker is again exactly 300 pixels down.
EDIT2
After noticing that the picker shows 300 pixels down , i decided to manually make it show 300pixels up , to point exactly on my button.
I used the following code :
- (IBAction)selectTopic:(UIControl *)sender {
//[ActionSheetStringPicker showPickerWithTitle:NSLocalizedString(#"CHOOSE_TOPIC", nil) rows:self.topics initialSelection:self.selectedIndex target:self successAction:#selector(topicWasSelected:element:) cancelAction:#selector(actionPickerCancelled:) origin:sender];
ActionSheetStringPicker *thePicker = [[ActionSheetStringPicker alloc] initWithTitle:NSLocalizedString(#"CHOOSE_TOPIC", nil) rows:self.topics initialSelection:self.selectedIndex target:self successAction:#selector(topicWasSelected:element:) cancelAction:#selector(actionPickerCancelled:) origin:sender];
CGRect pickerFrame = topicField.frame;
pickerFrame.size.height -= 300;
thePicker.presentFromRect = pickerFrame;
[thePicker showActionSheetPicker];
//when user picks a new topic we clean the titleField to make sure selected title of previous topic doesnt mix up with new topic
titleField.text = #"";
}
Amazingly the button once again appears in the same position 300pixels down. I start to believe that this one may not be the property to alter the position of the picker.
Any ideas ?
Setting the presentFromRect in your calling code won't make a difference since it will be reset based on the sender within the ActionSheetPicker code, instead you are going to need to modify the source code of the library.
The following (unmerged) commit on github should resolve the issue On iPad, set the popover to point properly at its container.
Basically within the AbstractActionSheetPicker.m file modify the - (void)presentPickerForView:(UIView *)aView method like the following
- (void)presentPickerForView:(UIView *)aView {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
self.presentFromRect = CGRectMake(0, 0, self.containerView.frame.size.width, self.containerView.frame.size.height);
[self configureAndPresentPopoverForView:aView];
}
else {
self.presentFromRect = aView.frame;
[self configureAndPresentActionSheetForView:aView];
}
}
After a brief look at the code, I would say that you want to make sure that the presentFromRect on the ActionPicker object is in the coordinates of the container that you are passing in on the init. For instance if I had one big view that contained a button:
This is untested:
UIView* someBigView = ... // get the big view
UIButton* someButton = ... // get the button that the big view contains
ActionSheetDatePicker* thePicker = [[ActionSheetDatePicker alloc] initWithTitle:#"Some Title"
datePickerMode:UIDatePickerModeDate
selectedDate:[NSDate date]
target:self
action:#selector(someMethod:)
origin:someBigView];
//the arrow should be pointing at the button
thePicker.presentFromRect = someButton.frame;
[thePicker showActionSheetPicker];
In my opinion, this library has a pretty big flaw in the fact that it takes an origin parameter that can be a button item or a container. It requires that you look at the source to understand it, instead of being (somewhat) obvious from the interface.

Resources