I'm looking for some help integrating UIAccelerometer into my cocos2d based application. My current design is roughly the following:
1 -- My HelloWorldLayer layer has a private variable -- a class called Manager -- that I will refer to as the data manager. It is the primary data management class that provides information to the UI.
2 -- The HelloWorldLayer's update method calls to the data manager's update method.
3 -- The data manger allocates a new object -- a class called accelerationMeter -- that provides accelerometer data and updates a custom data object that I'm using to track the devices current acceleration.
4 -- The accelerationMeter class sets up the accelerometer like so:
-(id) init
{
if (self == [super init])
{
// the below call is only used if this object extends CCLayer. Right now it extends NSObject
// self.isAccelerometerEnabled = YES;
[[UIAccelerometer sharedAccelerometer] setUpdateInterval: 1/60];
[[UIAccelerometer sharedAccelerometer] setDelegate: self];
// my data type to store acceleration information
self.currVector = [[vector alloc] init];
}
return self;
}
// method called when the UIAccelerometer updates
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
[self currVector].x = acceleration.x;
[self currVector].y = acceleration.y;
NSLog([NSString stringWithFormat:#"accelerometer: x = %f, y = %f",self.currVector.x,self.currVector.y]);
}
5 -- After (seemingly exactly) 1 second of successful data collection from the UIAccelerometer, the NSLog line in the "accelerometer" method stoops logging. Therefore, the delegated method stops being called.
6 -- As per request, here is the code I use to integrate the accelerometer:
// source: HelloWorldLayer.mm
// purpose: update scene
-(void) update: (ccTime) dt
{
<snip>
world->Step(dt, velocityIterations, positionIterations);
[self updateData];
<snip>
}
// source: HelloWorldLayer.mm
// purpose: update data and use that for the accelerometer display
-(void) updateData
{
if(dataManager)
{
[dataManager update]
<snip>
float accelX = [dataManager currentAcceleration].x;
float accelY = [dataManager currentAcceleration].y;
<snip>
}
}
// source: Manager.m (the data manager class)
// called by updater method copied above this
-(void) update
{
// replace outdated current accleration with the updated current accel
// right now, the accelMonitor class just returns the value of the current acceleration so I will omit the monitor class
currentAcceleration = [accelMonitor getCurrent];
NSLog(#"Manger: Update called");
}
// source accelerationMeter.m
// called by (through an intermediate class) Manager
// I have verified that this method continues to be called after the accelerometer stops working
-(vector*) getCurrentAcceleration
{
NSLog(#"accelerationMeter: getCurrentAcceleration called");
return self.currVector;
}
Note I am not using the IOS simulator -- I am reading the logs from the console of my device.
My main questions are the following:
A -- Why could the accelerometer's delegated method stop being executed?
B -- How can I resolve this so that I can make use of the accelerometer data for > 1 second?
Solved!
I ended up adding the accelerationMeter as a node to the HelloWorldLayer layer. I think that this had something to do with the runloop going out of scope or switching modes, which would therefore stop the accelerometer from collecting data, though I'm unsure.
Related
'Cause of the difficulties I found combining UITableView and SpriteKit Framework I decided to develop a custom SKTableView (provided with full scrolling system). Everything works really fine but I have serious problem understanding an error I get during the update process.
My SKTableView shows the user a list of items in alphabetical order. Due to the tricky algorithm I should have create in order to update this list (add a cell in a defined position, refresh the headers and scroll down all of the items), I decided to simply update the database and reload the list (by removing existing content and recreate it) while showing asynchrony a notification to the user.
What is happen is the application to success reload the list once, once again, then after some random updates ... here comes the chaos
Issues
The application crashes giving me EXC_BAD_ACCESS during the removeAllChildren methods.
The application crashes with the same error during a for statement (???) or during other statements
The application crashes giving me jet_context::set_fragment_texture... error.
Debug:
The console window doesn't show any kind of information.
I can't monitoring the application using 'Allocation' or 'Zombies' instruments because it critically slow down the application. It takes more than 2 minutes to even load the SKTableView during the init method.
Code
Interface
/** Container for all the table items. */
#property (nonatomic, readonly) SKNode *nodeContainer;
Initialization
- (instancetype)init
{
if (self = [super init]) {
...
Create the style of the SKNode
...
// Container initialization
_nodeContainer = [[SKNode alloc] init];
_nodeContainer.position = CGPointZero;
_nodeContainer.zPosition = 0;
[self addChild:_nodeContainer];
// Generate the content
[self generateContent];
}
return self;
}
Populate the table
- (void)generateContent
{
// Checks if the node exists, if it does, remove all of its children
// Note: used for the recreation of the list
if (_nodeContainer != nil)
[_nodeContainer removeAllChildren];
...
Initializes several SKSpriteNode and SKLabelNode
...
[_nodeContainer addChild:imgItem];
[_nodeContainer addChild:labelItem];
}
Reload the content
...
Update the database
...
[self showProgressNotification];
// Reload the content showing a notification
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Reload the content
[self generateContent];
dispatch_async(dispatch_get_main_queue(), ^{
[self hideProgressNotification];
});
});
I really cannot figure it out what's happening. The code crashes overtime in a different line without a logic. I mean, is this the right way to remove and recreate items? Any advise?
I'm using Magical Record 2.3.0 beta 5 and I have troubles understanding how to get my NSManagedObjects for the current thread. I have a long running NSOperation where I need my PSPlayer (NSManagedObject).
When I init the NSOperation, I keep an id of my PSPlayer and re-fetch the same object in the operation's main method. According to Apple that the way to do it.
#implementation TAPlayerUpdateOperation
- (instancetype)initWithPlayer:(PSPlayer *)player;
{
self = [super init];
if (self) {
self.playerMD5Id = player.md5Id;
}
}
- (void)main
{
#autoreleasepool {
__block BOOL keepUpdating = YES;
PSPlayer *player = [[PSPlayer MR_findAllWithPredicate:[NSPredicate predicateWithFormat:#"md5Id == %#", self.playerMD5Id]] firstObject];
NSLog(#"player.md5Id = %#", player.md5Id);
// rest of my operation logic
}
}
#end
When I run my app with -com.apple.CoreData.ConcurrencyDebug 1, I get a crash when accessing the property in the NSLog statement.
What is the correct way to get my NSManagedObject so that it is safe for the current thread?
I've pinned the problem down to the following snippet where it crashes as well.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
PSPlayer *player =[[PSPlayer MR_findAll] firstObject];
NSLog(#"player = %#", player.name);
});
cheers,
Jan
You need to ensure that everything is saved and merged before the fetch would work. If you're using MR then it's better to take the managed object and call inContext: on it supplying the other context and have it do the work (it also avoids a predicate).
I expect the crash is because you use player.md5Id instead of self.playerMD5Id so you're accessinh the managed object on the wrong thread.
captureOutput:didOutputMetadataObjects:fromConnection: Deleagate firing Multiple times. I need to pass scanned value to server so multiple calls happens to server for one scan
Here is the same question
Delegate method being invoked multiple times, even after returning to a view
As Apple documentation says : "this method may be called frequently, your implementation should be efficient to prevent capture performance problems, including dropped metadata objects".
handle multiple invoke do the following :
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
id capturedData;
if ([metadataObjects count] > 0) {
// handle your captured data here
[self performSelectorOnMainThread:#selector(stopReading:) withObject:capturedData waitUntilDone:NO];
}
}
the stopReading: method looks (assuming your _session is AVCaptureSession object and _prevLayer is AVCaptureVideoPreviewLayer you used earlier) :
-(void)stopReading:(id) data{
NSLog(#"stop reading");
[_session stopRunning];
_session = nil;
[_prevLayer removeFromSuperlayer];
// do what you want with captured data
[self.delegate didScanBarCodeWithContext:data];
}
Is it possible and practical to create a Core Data class method that will return the current instance of managedObjectContext? I am wondering so that I can segue to other controllers and load modal views without having to pass the managedObjectContext.
Also if I am using Core Data with dispatch_async I know I need to create my own instance of managedObjectContext but I can use the same coordinator. Will this make the information accessible both inside the dispatch_async and in the main thread?
I am basically using the dispatch_async to get data from the API and store it while the user is using the application.
In the past, I've created a Core Data manager singleton class that has simplified things. Here is an example, but this is pre-iOS5/ARC, so some changes need to be made.
I had a similar issue when trying to asynchronously getting data from my server to the app. My method is a bit different, but basically here it is (this is a 4.3 project, so no ARC):
The following methods are in my DataUpdater singleton. This first method is called at app startup:
- (void) update { //download the updates on a new thread
[NSThread detachNewThreadSelector:#selector(updateThread)
toTarget:self withObject:nil];
}
It initializes a thread with this selector, which is responsible only for downloading the content from the API, then passing it back to the main thread to be saved.
- (void) updateThread { //the actual update thread
//New thread, new auto-release pool
//(dunno if you need to do anything fancy for ARC)
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//...
//YOUR CODE TO DOWNLOAD (BUT *NOT* SAVE) DATA FROM THE SERVER
//DON'T CREATE ANY MANAGED OBJECTS HERE
//...
//Pass the data to the main thread to perform
//the commit to the Core Data Model
[self performSelectorOnMainThread:#selector(saveUpdate:)
withObject:data waitUntilDone:NO];
//kill the thread & the auto-release pool
[NSThread exit];
[pool release];
}
Now that we're back on the main thread, the data is added to the Core Data Model and then the context is saved.
- (void) saveUpdate:(NSArray *) data {
//add the objects to your Core Data Model
//and save context
NSError * error = nil;
[[[CoreManager defaultCoreManager] CoreContext] save:&error];
if (error) {
[NSException raise:#"Unable to save data update"
format:#"Reason: %#", [error localizedDescription]];
} else {
[[NSNotificationCenter defaultCenter] postNotification:
[NSNotification notificationWithName:#"DONE" object:nil]];
}
}
Dealing with the first part of the question only (you shouldnt really ask multiple questions!) you don't have to pass the managed object context around - presumably you are passing a managed object? In that case the context is available as a property of the managed object itself - .managedObjectContext.
i have a method, in which i want to accomplish a given task, however, the asynchronous commands and delegates made it difficult
i can do this :
- (void) fooPart1
{
...
SomeAssynchronousMethos * assync = [[SomeAssynchronousMethos alloc] init];
assync.delegate = self;
[assync start];
}
- (void) fooPart2
{
...
possibly some other assync
}
- (void)someAssynchronousMethosDelegateDidiFinish
{
[self fooPart2];
}
But isn't there a way to do smith. like this
- (void) foo
{
...
SomeAssynchronousMethos * assync = [[SomeAssynchronousMethos alloc] init];
assync.delegate = self;
[assync start];
wait for signal, but class is not blocked
...
possibly some other assync
}
- (void)someAssynchronousMethosDelegateDidiFinish
{
continue in foo after [assync start]
}
I don't like the idea of splitting a function to 2 or more parts, but is this the way how it is done in cocoa? or is there a better practice?
why i dont like this concept and searching for a better way of doing it :
lets say, i want to use a variable only for compleating a task - if i have everything in one function, i just use it, and than the var dies as i leave the function, if its split, i have to keep the var somehow around, until it doesnt finish
the code becomes fragmented and more difficult to read and maintain
may lead to bug
i end up with a set of part function, that needs to be called in precise order to accomplish one task (for which one function would be more suitable)
i used to make a thread and do only synchronous calls there, but not everything supports a synchronous call
what would be realy nice, is to have smth, like
- (void) foo
{
...
int smth = 5;
SomeAssynchronousMethos * assync = [[SomeAssynchronousMethos alloc] init];
assync.delegate = self;
#freez([assync start]);
// when freez - the local function variables are frozen
// (next commands in function are not excuted until unfreez)
// from outer look, it looks like the function finished
// however when unfreeze, it is called from this point on
//int smth is still 5
}
- (void)someAssynchronousMethosDelegateDidiFinish
{
#unfreez([assync start]);
}
when the execution would reach freez, it would store all local vars allocated in function and when called unfreez, it would continue from that point on, when it was freez with that command
This seems like an ideal application of a completion handler block.
Alter your start method to take a parameter which is a block and call it like so:
- (void) fooPart1
{
...
SomeAssynchronousMethos * assync = [[SomeAssynchronousMethos alloc] init];
[assync startOnComplete: ^(NSError* error) // example, you can have any params or none
{
// handle error if not nil
if (error != nil)
{
// do something with it
}
// code to do on completion
}];
}
Your start method would look something like this
-(void) startOnComplete: (void(^)(NSError*)) completionBlock
{
// copy the block somewhere
theSavedCompletionBlock = [completionBlock copy];
// kick off async operation
}
-(void) someMethodThatRunsAttheEndOfTheAsyncOp
{
theSavedCompletionBlock(nilOrError);
[theSavedCompletionBlock release];
}