CCLabelTTF changing string causes EXC_BAD_ACCESS - ios

First off, as a disclaimer, I am new to objective-c, xcode, and cocos2d. I have found a way in my app to refresh a screen conveniently, but I don't know if it is bad practice. Here's what I am doing. I have a class called Player with a variable NSString *name. I am displaying this and several other variables on the screen using this code in a function:
label = [CCLabelTTF labelWithString:string fontName:GLOBAL_FONT fontSize:font_size ];
label.color = color_back;
label.position = ccp(x+1, y-1);
[self addChild:label];
When a button is pressed, I am modifying player->name along with several other variables. Because several variable are changing (on this screen and eventually others) when the button is pressed I also set a flag to indicate that the screen needs to be refreshed. I then check this code with a scheduler:
if(panelPrev != currentPanel || refreshScreen) //do we need to initialize the panel?
{
[self removeAllChildrenWithCleanup:true]; //clear all objects from display
//Decide which objects to display
switch (G_display_panel) {
case P_Main:
[Display_Main init_Panel:self];
break;
case P_NewGame:
[Display_New init_Panel:self];
break;
default:
break;
}
refreshScreen = false;
}
My first question: Is this an acceptable way to display things to the screen and refresh them? It seemed much more convenient than updating every variable that is being displayed. The buttons are not being pressed very often so I am not concerned about performance.
Second: If it is ok to do it this way, why is it that when I press a button and change the value of player->name I am getting this: "Thread 1: EXC_BAD_ACCESS (code=1, address=...)"? If I step through with the debugger the value gets assigned to player->name correctly and the screen refresh works. But if I just let it run it gets the EXC_BAD_ACCESS when I try to access player->name and the data looks corrupted (e.g. (NSString *) name = 0x15927f80 when I am expecting (NSString *) name = #"Bob").
Some additional details.
I am not setting refreshScreen to 'true' until after changing the value of player->name
To prevent refreshing before the value was truly changed, I set a delay on the refresh. After the button was pressed I would modify player->name and wait about 10 seconds but I would still see the same problem.
Any ideas? Thanks.

try this:
[self addChild:label];

I figured out the problem. It was a memory management issue. I added a getter and setter for the variable using the example specified here: developer.apple.com/library/mac/documentation/Cocoa/Conceptual/… –

Related

Drawing static full screen images using DirectX11

My question is as follows. In most tutorials that I've seen there is a setup part of DirectX11 where you do something like this:
// Set the refresh rate of the back buffer.
if(m_vsync_enabled)
{
swapChainDesc.BufferDesc.RefreshRate.Numerator = numerator;
swapChainDesc.BufferDesc.RefreshRate.Denominator = denominator;
}
else
{
swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
}
Which either sets the refresh to be as fast as possible or synched with the monitor.
However in the application that I need I only want to refresh the screen when I tell the system to do it. Is there any way to do this?
These numbers have nothing to do with the actual refreshing, which happens when you invoke Present. You can call it once per second and screen will be refreshed just once.

tvOS: Focus not moving correctly

I have a UIView with two buttons on it. In the MyView class I have this code:
-(BOOL) canBecomeFocused {
return YES;
}
-(NSArray<id<UIFocusEnvironment>> *)preferredFocusEnvironments {
return #[_editButton, _addButton];
}
-(IBAction) editTapped:(id) sender {
BOOL editing = !tableViewController.editing;
[_editButton setTitle:editing ? #"Done" : #"Edit" forState:UIControlStateNormal];
_addButton.hidden = !editing;
[tableViewController setEditing:editing animated:YES];
}
The basic idea is that the user can move the focus to the edit button, which can then make the Add button appear.
The problem started because every time I tapped the edit button, focus would shift to the table view. I would actually like it to move to the Add button. I also want it so that when editing it deactivated, the edit button keeps the focus. but again it's shifting down to the table view.
So I tried the above code. This works in that focus can move to the view and on to the button. But once it's there, I cannot get it to move anywhere else.
Everything I've read says just override preferredFocusEnvironments but so far I've not been able to get this to work. Focus keeps going to a button then refusing to move anywhere else.
Any ideas?
If anybody is facing this issue, Just check if you are getting the following debug message printed in the console.
WARNING: Calling updateFocusIfNeeded while a focus update is in progress. This call will be ignored.
I had the following code :
// MARK: - Focus Environment
var viewToBeFocused: UIView?
func updateFocus() {
setNeedsFocusUpdate()
updateFocusIfNeeded()
}
override var preferredFocusEnvironments: [UIFocusEnvironment] {
if let viewToBeFocused = self.viewToBeFocused {
self.viewToBeFocused = nil
return [viewToBeFocused]
}
return super.preferredFocusEnvironments
}
I was calling the updateFocus() method multiple times while viewToBeFocused was either nil or some other view. Debugging the focus issues mainly between transition is really difficult. You should have patience.
Important to note: This depends on your use case, but if you want to
update the focus right after a viewcontroller transition (backward
navigation), You might have to set the following in viewDidLoad:
restoresFocusAfterTransition = false // default is true
If this is true, the view controller will have the tendancy to focus the last focused view even if we force the focus update by calling updateFocusIfNeeded(). In this case , since a focus update is already in process, you will get the warning as mentioned before at the top of this answer.
Debug focus issue
Use the following link to debug the focus issues: https://developer.apple.com/documentation/uikit/focus_interactions/debugging_focus_issues_in_your_app
Enable the focus debugger first under Edit scheme > Arguments passed on launch:
-UIFocusLoggingEnabled YES
This will log all the attempts made by the focus engine to update the focus. This is really helpful.
You can override the preferredFocusEnviromnets with the following logic:
-(NSArray<id<UIFocusEnvironment>> *)preferredFocusEnvironments {
if (condition) {
return #[_editButton];
}
else {
return #[_addButton];
}
}
After setting it, you can call
[_myView setNeedsFocusUpdate];
[_myView updateFocusIfNeeded];
The condition could be BOOL condition = tableViewController.editing; or sg like that.
If that now works, you can call it with a delay (0.1 sec or so).

UITextField input every time new iteration

I'm new to Objective-C and Xcode, and I have one problem, I tried looking in the Internet, but didn't find anything.
I have "game" and there I have a screen with two text fields, button and text view.User inputs integer values and taps the button. After tapping the button some functions(or, methods) are called. Method that is called after typing the button:
- (IBAction)okButtonTapped:(id)sender {
int save1=100;
int save2=100;
int save13=1;
int save22=1;
int save12=1;
int save23=1;
while(save13 !=0 && save23 !=0){
[self yourturn:&save1 heap2:&save2];
save12= save1;
save22=save2;
[self compturn:&save12 heap2:&save22];
save13=save12;
save23=save22;
save1=save13;
save2=save23;
}
}
Here some methods are called. And in this methods I use this code to save values from textfields that user inputs:
_heapNumberInt=[self.heapNumberTextField.text intValue];
_thingsNumberInt=[self.thingsNumberTextField.text intValue];
And the question is how to make users input new values in the textfield every time when there is new iteration in while loop?
Sorry for my English(it's not my native language) and for my long question.
All project you can download here
P.S. "game" is very simple: there are 2 heaps with 100 things each, user chooses his turn and then he inputs values: heap number(1 or 2 heap) and number of things he wants to take from the heap. Then there is computer's turn. And looser is someone who can't take things from any heap. It is real game called NIM.(but here I made only 2 heaps(not 3)).
Probably you need to read Event Handling Guide
https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009541
About the question, for setting focus to the input you should use
[self.heapNumberTextField becomeFirstResponder];
UPDATE:
As I understand you need to:
_heapNumberInt = [self.heapNumberTextField.text intValue]; // get value
[self.heapNumberTextField setEditable:NO]; // disable editing to calculate
[self calculate];
self.heapNumberTextField.text = #""; // clean UITextField
[self.heapNumberTextField setEditable:YES]; // allow editing
[self.heapNumberTextField becomeFirstResponder]; // set focus to the textfield

How to wait for button press in objective c

I have an array of objects (scaleNotes) that are assigned to buttons that I would like to iterate through. I want the app to wait for the first set of buttons to be pressed, then to wait for the second, and so on. However, with the function I currently have the app freezes.
The method that contains the array:
-(void)fingerScale :(UIButton*)button1 :(UIButton*)button2 :(UIButton*)button3 :(UIButton*)button4 :(UILabel*)label {
Note *note = [[Note alloc]init];
for (int i = 0; i < [_scaleNotes count]; i++) {
note = _scaleNotes[i];
label.text = note.noteName;
[note waitForNote:button1 :button2 :button3 :button4 :note];
NSLog(#"Waiting... %i", i);
}
}
The "waitForNote" method:
-(void)waitForNote:(UIButton *)button1 :(UIButton *)button2 :(UIButton *)button3 :(UIButton *)button4 :(Note*)Note {
bool loop = YES;
while (loop) {
switch ([Note.fingering count]) {
case 0:
loop = NO;
break;
case 1:
button1 = Note.fingering[0];
if (button1.touchInside) {
loop = NO;
}
break;
case 2:
button1 = Note.fingering[0];
button2 = Note.fingering[1];
if (button1.touchInside && button2.touchInside) {
loop = NO;
}
break;
case 3:
button1 = Note.fingering[0];
button2 = Note.fingering[1];
button3 = Note.fingering[2];
if (button1.touchInside && button2.touchInside && button3.touchInside) {
loop = NO;
}
break;
default:
break;
}
}
}
I have been told that using addTarget:action:forControlEvents may solve my problem instead of using a while loop, but I am unsure about how to implement that into my code. Please help.
Your while loop is an infinite loop, and that's why your app appears to freeze. Most GUI systems -- iOS included -- won't work that way. You have to give the app's event loop, or run loop, time to gather and process events.
-addTarget:action:forControlEvents: will be part of the solution, but you really need to spend some time learning more about how apps and controls work in general. Briefly, your controls should be connected to appropriate actions; if you want to enforce some order for the buttons you might enable or disable some buttons as necessary.
To expand on Caleb's answer a little bit:
iOS, like most modern interactive OS'es, is event-driven.
You write code that responds to events. The OS detects events, and then invokes the methods in your app that respond to those events.
You do NOT write a while loop that keeps looping, waiting for things to happen.
For buttons, you create methods of type IBAction, and you connect them to your buttons (usually connected to a "touch up inside" event.) Then, when the user taps and releases a button, the system calls your action method.
For a slider, you would write an action method and attach it to the "value changed" event for the slider. Then, when the user changed the value of the slider the system would call you.
So for your buttons you would write an action method and attach it to your buttons. (It's more common to create buttons and attach them to actions in Interface Builder, but you can also create them in code and then attach them using the -addTarget:action:forControlEvents: method you mentioned.)
If you've got multiple buttons that do the same thing but with different values, you might want to attach all the buttons to the same IBAction method, and then put different tag values on each button. Then in your IBAction method, look at the tag on the sender (The button that invoked the action) and use that to figure out which button was pressed.

Check if one method has been run in a different method

I'm writing some code in Xcode for an iPhone app and I want to be able to detect if a method has been run (i.e. a button was pressed, causing that method to run) in another method (I want to use an if statement so that if the button was pressed it will do this, but if it wasn't then it will do something else).
There is no has_method_been_run() function but you can check to see if the state was changed.
For example say method button_clicked() calls method change_font_to_blue(). In this case you can check to see if the font is blue and there for the method was called.
That's a very basic example of course but you could check any number of variables / the state of the UI to see if it was changed.
OR you can add a boolean to an object and just set it to true when you execute you're method that you're watching.
If your example is simply a button press I would change the UIButton's selected state
- (IBAction)buttonSelected:(UIButton *)sender {
sender.selected = YES;
// OR:
// self.myButton.selected = YES;
}
- (void)otherMethod {
if (self.myButton.isSelected) {
// button has been run through the selector method
// if you want, reset button's selected state
self.myButton.selected = NO;
} else {
// button has NOT been run through the selector method
}
}
This is a simple idea and by default the selected state of a UIButton is not visually different. If you want it to be visually changed then you can simply go into IB and change the visuals there for the selected state (including the title):
Then when the button is set to selected (self.myButton.selected = YES;) it will automatically change what the button looks like!

Resources