UILabel text is not updating on iPad - ios

We have a delegate method which will be called for approximately 20 times in a second. In the delegate method we are updating our UILabel which represents the counter like below mentioned code:
- (void) counterUpdated:(NSString *) value
{
lblCounter.text = [NSString stringWithString:value];
// [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
// [lblCounter setNeedDisplay];
}
I read similar problems in stack overflow and I implemented the solutions over there and I checked with keeping [lblCounter setNeedDisplay]; method and [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]]; after updating lblCounter, but it is not working well as expected.
Any pointers?

Try using Grand Central Dispatch in order to run this in the main thread:
dispatch_async(dispatch_get_main_queue(), ^{
lblCounter.text = value;
});

Related

Dropbox DBRestClient/DBRestClientDelegate execute on a thread

I am using the dropbox API with DBRESTClient and DBRestClientDelegate in Dropbox-iOS-SDK
My issue is that I need these to run on a background thread.
When I call the [restClient loadMetadata] I do not get a response to - restClient:loadedMetadata: unless I begin call from the main thread.
Is there a simple workaround/library that I can use which will allow a delegate response on a thread ? I have tried Dropblocks which uses blocks but no luck.
I noticed "Make sure you call DBRestClient methods from the main thread or a thread that has a run loop. Otherwise the delegate methods won't be called." on the Dropbox Page
https://www.dropbox.com/developers-v1/core/start/ios
I used a runloop and it functions on a thread now
This is using a completion block Similarly you could use the delegate to set the flag to NO
self.inQuery = YES;
[self loadMetaDataWithPath:rootFolder mediaType:#(mediaType) completion:^(BOOL complete) {
self.inQuery = NO;
}];
#autoreleasepool {
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
DDLogError(#"currentRunLoop %#",[NSDate date]);
}while(self.inQuery);
}

MobileVLCKit thumbnailer issue

I want to create a CVPixelBuffer, since it need a CGImageRef I used [VLCThumbnailer fetchThumbnail] method and crashed with
"Assertion failed: ([thumbnailer dataPointer] == *p_pixels), function
unlock, file
/Users/apple/opensource/vlc-ios/ImportedSources/VLCKit/Sources/VLCMediaThumbnailer.m,
line 74." neither can I find the route"/Users/apple".
Here is the code:
- (void)viewDidLoad {NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(catchThumbnail) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];}
- (void)catchThumbnail {
if (self.vlcPlayer.hasVideoOut) {
[self.thumbnailer fetchThumbnail];
}}
// VLCMediaThumbnailerDelegate
-(void)mediaThumbnailer:(VLCMediaThumbnailer *)mediaThumbnailer didFinishThumbnail:(CGImageRef)thumbnail {
NSLog(#"-----%#------",thumbnail);
}
worth mentioning: first time it logged :MobileVLCKitPlayer[2736:1068033] -----<CGImage 0x7f803bed56e0>------,but SECOND time crashed
Could someone help me,thanks a lot! :)
I have fixed it, if somebody facing the same issue, remember to set thumbnailer.thumbnail = nil after handling it everytime :)

Call an action at specific intervals in iOS

I am trying to invoke a function that contains ccactioninterval in Cocos3d. I want to call that function at specific time intervals.When I tried NSTimer , i found that it works sometimes and sometimes not.
NSTimer makeTarget=[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(createTargets) userInfo:nil repeats:YES];
Here createTargets is the function that contains action events. when i run the function straightit works fine for single time. Problem comes when i try to schedule it. I ve tried different methods already explained for related questions . But nothing worked for me. . . .
Here is the code
-(void) addTargets {
NSTimer *makeTarget = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self selector:#selector(createTargets) userInfo:nil repeats:YES];
}
-(void)createTargets {
CC3MeshNode *target = (CC3MeshNode*)[self getNodeNamed: #"obj1"];
int minVal=-5;
int maxVal=5;
float avgVal;
avgVal = maxVal- minVal;
float Value = ((float)arc4random()/ARC4RANDOM_MAX)*avgVal+minVal ;
[target setLocation:cc3v(Value, 5.0, 0.0)];
CCActionInterval *moveTarget = [CC3MoveBy actionWithDuration:7.0 moveBy:cc3v(0.0, -10.0, 0.0)];
CCActionInterval *removeTarget = [CCCallFuncN actionWithTarget:self selector:#selector(removeTarget:)];
[target runAction:[CCSequence actionOne:moveTarget two:removeTarget]];
}
-(void)removeTarget:(CC3MeshNode*)targ {
[self removeChild:targ];
targ=nil;
}
Without much code its hard to tell what you issues is, but here are some things to try apologies if any of this is obvious.
Are you holding onto a reference to the timer?
This might be useful for debugging. If you have a property called makeTargetTimer, then you could do this:
NSTimer * makeTargetTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(createTargets) userInfo:nil repeats:YES];
self.makeTargetTimer = makeTargetTimer // Save to a property for later use (or just use an iVar)
The only way to stop a re-occurring timer is to invalidate it. Therefore you could check to see if its been invalidated.
BOOL isInvalidated = [self.makeTargetTimer isValid];
Also you might want to do this in your dealloc method anyway:
- (void) dealloc {
[_makeTargetTimer invalidate]; // Stops the timer from firing (Assumes ARC)
}
Are you scrolling when the even should be received?
If you want the timer to be fired while scrolling then you need to use NSRunLoopCommonModes. There is a excellent expiation in this question.
[[NSRunLoop currentRunLoop] addTimer:makeTargetTimer forMode:NSRunLoopCommonModes];
What is your implementation of createTargets like?
Have you put NSLog statements on the body of this method. Are you certain its not being called?

BAD EXC in [[NSRunLoop currentRunLoop] runMode:* beforeDate:*];

I'm trying to do some stress testing on my app with a unit test, and I'm running into some problems. Below is my code:
//Stress test api and core data
__block BOOL done = NO;
for (int i = 0; i < 100 ; i++) {
DLog(#"in here");
[viewController createList:testList
success:^(Lists *list) {
DLog(#"in success block : %d", i);
STAssertNotNil(list, #"list is not nil");
done = (i == 99);
}
failure:^(NSError *error) {
DLog(#"in fail block");
}
];
}
#autoreleasepool {
while (!done) {
// This executes another run loop.
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
The problem is, after several iterations, I get a bad access error on the line
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
I've already put the while loop in the #autorelease because of this post. I'm using ARC on the project, so I don't know if that's contributing to the problem..? I need to use the NSRunLoop to force the unit test to wait for the block to complete.
Has anyone run into this problem?
In a similar situation, I did it differently and it worked fine. What I did was in the main test, used dispatch_group_async to the normal queue, and then in the main test waited for the group to finish. That works just fine and you don't mess with the unit test's runloop.
if for some reason the above is not acceptable, then try not using any autorelease pool to see if that works If it does, then move it into the while look. With ARC the need for an autorelease pool is greatly diminished. You can observe memory usage using Instruements too.

How do I execute my method when the UIView loads?

I have a view-based template app and have UILabel & UIButton. For debugging purposes I'm showing and hiding the button whilst changing the UILabel.text.
In C++ I would 'thread root();' to execute the root method but I don't know how to in Objective-c. How to run my 'root' method once the view loads?
-(void) root
{
[bombButton1 setHidden:NO];
int s = 0;
int j = 10;
while ( s < j )
{
[bombButton1 setHidden:YES];
NSString *debugLabelString = [NSString stringWithFormat:#"%d", s];
debugLabel.text=debugLabelString;
s++;
}
Edit:
Right, now I have: (but I get ERROR: Expected method body on the "-(void) rootMethod: NSTimer * timer {" line)
-(void) applicationDidFinishLaunching : (UIApplication *) application {
spawnTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target:self selector:#selector(rootMethod:) userInfo:nil repeats: YES];
}
-(void) rootMethod: NSTimer * spawnTimer {
int s = 0;
int j = 10;
while ( s < j )
{
NSString *debugLabelString = [NSString stringWithFormat:#"%d", s];
debugLabel.text=debugLabelString;
//debugLabel.text=#"debug test complete";
s++;
}
}
Several ways to do this, I think. Here's one:
[self performSelectorInBackground:#selector(root) withObject:nil];
You'd make this call in say, your -(void)viewDidAppear: method.
You may run into issues running code on threads other than the main thread that tries to manipulate the UI.
That sleep(1) is worrisome. You could use a repeating NSTimer instead and eliminate the sleep(1) entirely. Something like:
[NSTimer scheduledTimerWithInterval:2.0 target:self
selector:#selector(root:) userInfo:nil repeats:YES];
For NSTimer, you'd have to change your method, root, to have a signature like
- (void)root:(NSTimer*)theTimer
You need to implement a called viewDidLoad.
- (void) viewDidLoad() {
// your code here
}
I'm sure you have your reasons, but you really shouldn't iteract with UI components in anything other than the UI thread. What you actually need to do is use an NSTimer to call a method on the UI thread multiple times.
What you should be doing is performSelectorOnMainThread when you want to update the UI Thread.
Do your running in the background and update variables that will contain the updated values, then use performSelectorOnMainThread on the View, sending it to a method that will merely update the Textbox with the data in the variables.
You can do anything in a background thread, except update the ui.
Edit: Furthermore I dont recommend using Timers in place of background threads, I have had instances when using Timers, where only so many get created and when I expected a background thread to fire, it never did. The timer actually never fired, even tho it was created.

Resources