I'm trying to debug my games code. I'm developing a game for iOS and my code uses a lot of IF statements. I would like to know if there is even a very small performance hit when using these.
Thanks
Of course there is a performance hit when branching.
But you can't make a reasonable program without branch.
So use the if, and if by profiling your program you detect a problem on a specific location in your code, try to see if you can reduce the numbers of branchings or to put them out of the loops. But don't pay too much attention to it as long as the code remains clear.
Most of the time, the first impact of numerous if is on readability and maintainability. But premature optimization is often a greater hit on those topics.
It depends on where you used your if statements, there are some performance regarding using if in the right way
I will state some of them
Always use the if that is most likely to happen before the else, use the cases that are more common before then use the ones that are less likely
try to use if before the loops,
For example
instead of this
BOOL isCase1 = [self isCase1];
for (int i = 0 ; i < 10000 ; i ++)
{
if(isCase1)
{
//do something
}
else
{
//do some other thing
}
}
use this
BOOL isCase1 = [self isCase1];
if(isCase1)
{
for (int i = 0 ; i < 10000 ; i ++)
{
}
}
else
{
for (int i = 0 ; i < 10000 ; i ++)
{
}
}
Dont assume that you will need to improve performance before you are sure, most of the time your performance is doing good, if you are sure that some code is causing performance issues improve it (dont premature optimize your code)
These are some of the cases, there are much more
UPDATE:
Some other helpful things you could do, cache your boolean checking statments
for example
Instead of
for (int i = 0 ; i < 10000 ; i ++)
{
if([self isCase1]) //Do some thing
}
use
//Cache the result inside a variable
BOOL isCase = [self isCase1];
for (int i = 0 ; i < 10000 ; i ++)
{
if(isCase) //Do some thing
}
Related
When i try to use the ParseObject to store the local data, i find that the performance is very bad, when i execute below codes at IOS 5, will take about 1 - 2 secs for every loop. But seems that the performance is ok at emulator and iphone 5s.
for(int i = 0; i < 20; i++){
PFObject *pfObj = [PFObject objectWithClassName:#"TestStore"];
pfObj[#"TestStore_ID"] = userId;
pfObj[#"TestStore_URL"] = avatarUrl;
[pfObj pinWithName:#"TestStore"];
}
The pinWithName: method is synchronous and pinning executes SQLite statements under the hood, which can be quite slow. You should try using pinInBackgroundWithName: to execute this outside of the main thread.
I have an app I call memory eater, which is meant to force other applications to be dumped by the os. It does this by consuming lots of memory over time until it is terminated due to memory pressure. In order to consume memory I basically make copies of JPEG representations of data:
-(IBAction)didTapStartButton:(id)sender{
int i = 200;
while (i>0) {
NSData* data = [UIImagePNGRepresentation(self.image) mutableCopy] ;
[self.array addObject:[[data description] mutableCopy]];
[self.array addObject:data];
i--;
}
}
This was done entirely with trial and error, and I assume that there is a more straightforward way to consume lots and lots of memory.
You can use malloc() in a loop.
while (1) {
int *ptr = malloc(4096);
assert(ptr != NULL);
*ptr = 0;
}
The *ptr = 0 line is necessary to force the page to be dirty, otherwise you will consume address space instead of memory. The number 4096 ensures that each iteration through the loop will add exactly one dirty page to the address space, since 4096 is the most common page size.
I am sure this has already occured to someone but I could not find a trusted source (on Stackoverflow or elsewhere) to solve this.
I have to download a (finite) number of files. I don't know their size prior to downloading them. Their size can greatly change and I don't know it before beginning the download.
It can often happen that I have 9 really small files and 1 really big file.
If I use NSProgress with its "children" feature, I will very quickly show a completion of 90%, then the UI will appear to be stuck (even though it is not the case) since the last file is much bigger.
Here is an example code where I simulate a large file.
- (void)viewDidLoad
{
[super viewDidLoad];
nbTasks = 10;
mainProgress = [NSProgress progressWithTotalUnitCount:nbTasks];
[self launch];
}
- (void)launch {
for (int i = 0; i < nbTasks; ++i) {
[mainProgress becomeCurrentWithPendingUnitCount:1];
[self launchWithNumber:i];
[mainProgress resignCurrent];
}
}
- (void)launchWithNumber:(int)count {
int max = count == 0 ? 100 : 10;
NSProgress *localProgress = [NSProgress progressWithTotalUnitCount:max];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
for (int i = 0; i < max; ++i) {
localProgress.completedUnitCount++;
[NSThread sleepForTimeInterval:1];
}
});
}
How would you handle this case where you cannot change the becomeCurrentWithPendingUnitCount since you don't know its weight prior to begin downloading ?
EDIT: This is what I do for now:
First of all: I lied. I don't download files but data from a database, but it's the same problem in the end.
Before creating my root NSProgress, I download the number of objects from my backend (SELECT count(*) FROM ...). With this I can call becomeCurrentWithPendingUnitCount with the correct "weight" and the progress appears more "smooth".
Of course, this is far from ideal for me since I have to wait some time before showing the first NSProgress, and it makes me do more queries to the backend, but at least the experience is a bit better.
If I could remove this it would be much better. Any ideas?
I'm seeing an issue wherein CFReadStreamRead, as part of a streamed file upload, never returns.
This seems to happen only on iOS7 — and far more often when debugging against a physical device than in the simulator — or at least, it's far more evident there.
We have an HTTP (or HTTPS, the problem occurs either way, with a locally-hosted or remote server) POST of a file, via straight-line, blocking (non-event-driven) CFNetwork calls. It's a necessity of the C code calling this handler; there's no provision for callbacks.
That's well and good, the network calls are happening in background threads and/or via async dispatch.
The network code in question boils down to (removing error handling for brevity):
CFReadStreamRef upload = CFReadStreamCreateWithFile(
kCFAllocatorDefault, upload_file_url);
CFRelease(upload_file_url);
CFReadStreamOpen(upload);
CFReadStreamRef myReadStream = CFReadStreamCreateForStreamedHTTPRequest(
kCFAllocatorDefault, myRequest, upload);
CFReadStreamOpen(myReadStream);
CFIndex numBytesRead = CFReadStreamRead(myReadStream, buf, sizeof(buf));
// etc.
On its own, this code wants to hang immediately under iOS7. If I add a loop with some calls to usleep before it (checking CFReadStreamHasBytesAvailable along the way), it will almost always succeed. Every few hundred tries, it will still fail, never returning. Again, the main thread is unaffected.
I'd hoped the GM would clear up this behavior, but it's still present.
Adding a runloop/callback method to watch for bytes-available events has no effect - when the call hangs, no events are seen, either.
Any suggestions as to why this is happening, or how it can be prevented? Anyone else seeing different CFReadStream behavior under iOS 7?
I've try such nasty workaround and it works for me, problem is that I'm requesting delta values from server, so if something goes wrong I'm just fetching new delta value with, in general case it will not work (in logs I see that timeout kicks in sometimes). At least this prevents form permanent thread blocking and gives a chance to handle somehow this problem:
NSInteger readStreamReadWorkaround(CFReadStreamRef readStrem, UInt8 *buffer, CFIndex bufferLength) {
static dispatch_once_t onceToken;
static BOOL isProblematicOs = YES;
dispatch_once(&onceToken, ^{
isProblematicOs = [[UIDevice currentDevice].systemName compare: #"7.0" options: NSNumericSearch]!=NSOrderedAscending;
});
NSInteger readBytesCount = -2;
if (isProblematicOs) {
CFStreamStatus sStatus = CFReadStreamGetStatus(readStrem);
NSDate *date = [NSDate date];
while (YES) {
if(CFReadStreamHasBytesAvailable(readStrem)) {
readBytesCount = CFReadStreamRead(readStrem, buffer, bufferLength);
break;
}
sStatus = CFReadStreamGetStatus(readStrem);
if (sStatus!=kCFStreamStatusOpen && sStatus !=kCFStreamStatusAtEnd
|| [date timeIntervalSinceNow]<-15.0) {
break;
}
usleep(50000);
}
} else {
readBytesCount = CFReadStreamRead(readStrem, buffer, sizeof(buffer));
}
return readBytesCount;
}
I don't like this solution but so far I don't see an alternative.
I'm developing a BlackJack game for iOS. Keeping track of the current state and what needs to be done is becoming difficult. For example, I have a C++ class which keeps track of the current Game:
class Game {
queue<Player> playerQueue;
void hit();
void stand();
}
Currently I'm implementing it using events (Method A):
- (void)hitButtonPress:(id)sender {
game->hit();
}
void Game::hit() {
dealCard(playerQueue.top());
}
void Game::stand() {
playerQueue.pop();
goToNextPlayersTurn();
}
as more and more options are added to the game, creating events for each one is becoming tedious and hard to keep track of.
Another way I thought of implementing it is like so (Method B):
void Game::playersTurn(Player *player) {
dealCards(player);
while (true) {
string choice = waitForUserChoice();
if (choice == "stand") break;
if (choice == "hit")
dealCard(player);
// etc.
}
playerQueue.pop();
goToNextPlayersTurn();
}
Where waitForUserChoice is a special function that lets the user interact with the UIViewController and once the user presses a button, only then returns control back to the playersTurn function. In other words, it pauses the program until the user clicks on a button.
With method A, I need to split my functions up every time I need user interaction. Method B lets everything stay a bit more in control.
Essentially the difference between method A and B is the following:
A:
function A() {
initialize();
// now wait for user interaction by waiting for a call to CompleteA
}
function CompleteA() {
finalize();
}
B:
function B() {
initialize();
waitForUserInteraction();
finalize();
}
Notice how B keeps the code more organized. Is there even a way to do this with Objective-C? Or is there a different method which I haven't mentioned recommended instead?
A third option I can think of is using a finite state machine. I have heard a little about them, but I'm sure if that will help me in this case or not.
What is the recommended design pattern for my problem?
I understand the dilemma you are running into. When I first started iOS I had a very hard time wrapping my head around relinquishing control to and from the operating system.
In general iOS would encourage you to go with method A. Usually you have variables in your ViewController which are set in method A(), and then they are checked in CompleteA() to verify that A() ran first etc.
Regarding your question about Finite State Machines, I think that it may help you solve your problem. The very first thing I wrote in iOS was a FSM (there for this is pretty bad code) however you can take a look here (near the bottom of FlipsideViewController.m:
https://github.com/esromneb/ios-finite-state-machine
The general idea is that you put this in your .h file inside an #interface block
static int state = 0;
static int running = 0;
And in your .m you have this:
- (void) tick {
switch (state) {
case 0:
//this case only runs once for the fsm, so setup one time initializations
// next state
state = 1;
break;
case 1:
navBarStatus.topItem.title = #"Connecting...";
state = 2;
break;
case 2:
// if something happend we move on, if not we wait in the connecting stage
if( something )
state = 3;
else
state = 1;
break;
case 3:
// respond to something
// next state
state = 4;
break;
case 4:
// wait for user interaction
navBarStatus.topItem.title = #"Press a button!";
state = 4;
globalCommand = userInput;
// if user did something
if( globalCommand != 0 )
{
// go to state to consume user interaction
state = 5;
}
break;
case 5:
if( globalCommand == 6 )
{
// respond to command #6
}
if( globalCommand == 7 )
{
// respond to command #7
}
// go back and wait for user input
state = 4;
break;
default:
state = 0;
break;
}
if( running )
{
[self performSelector:#selector(tick) withObject:nil afterDelay:0.1];
}
}
In this example (modified from the one on github) globalCommand is an int representing the user's input. If globalCommand is 0, then the FSM just spins in state 4 until globalCommand is non zero.
To start the FSM, simply set running to 1 and call [self tick] from the viewController. The FSM will "tick" every 0.1 seconds until running is set to 0.
In my original FSM design I had to respond to user input AND network input from a windows computer running it's own software. In my design the windows PC was also running a similar but different FSM. For this design, I built two FIFO queue objects of commands using an NSMutuableArray. User interactions and network packet would enqueue commands into the queues, while the FSM would dequeue items and respond to them. I ended up using https://github.com/esromneb/ios-queue-object for the queues.
Please comment if you need any clarification.