I'm getting some warnings that somethings may not respond to a function.
#import "Lane.h"
#import "TrafficController.h"
#implementation Lane
#synthesize controller;
-(void)awakeFromNib
{
[controller registerLane:self]; -- 'TrafficController' may not respond to '-registerlane'
srandom(time(NULL));
[self start];
}
-(void)start
{
long newStartTime = random() % 200;
carStartTimer = [NSTimer scheduledTimerWithTimeInterval:newStartTime / 1000.0 target:self selector:#selector(startTimerFired:) userInfo:nil repeats:YES];
[carStartTimer retain];
}
-(void)startTimerFired: (NSTimer*)timer
{
//pick a random number of milliseconds to fire again at
long newStartTime = random() % 1500 + 500;
[timer setFireDate:[NSDate datewWithTimeIntervalSinceNow:newStartTime / 1000.0]];
[controller startCarFromLane:self]; - 'TrafficController' may not respond to '-startCarFromLane'
NSLog(#"Starting new car");
}
-(void)stop
{
[carStartTimer invalidate];
[carStartTimer release];
carStartTimer = nil;
}
#end
Does it mean that those functions arent declared in this or other header file? Or does it mean something else?
In your TrafficController.h, do you have a line like:
-(void) registerLane: (type) variablename;
If you don't, you should have
Do what #Dave says and let the complier know about your methods in your header file.
You can also quiet that message by manipulating the order of the methods in your implementation file. If the compiler has already seen the method (in this case -(void)registerLane:), then it won't bellyache when you call it later, even if it's not in your .h file.
That way you can have internal methods that aren't advertised as available in your .h but you can call them internally without compiler warnings. BUT, in most cases this is a mistake and you probably just forget to put it in the .h file.
Related
There are lots of ways to do this, but what is the current, modern, correct way for IOS 6 apps?
Here's what I'm doing now:
- (void)viewDidLoad
{
[super viewDidLoad];
__weak MyViewController *weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
// Do work that will take a long time
// Store data in member variables, etc.
// Update the UI
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.myTableView reloadData];
});
}
}
With ARC, I don't think the __weak reference is necessary, but I'm not 100% sure.
What you're doing is completely the right way to go! The weak reference is needed when you use blocks and is totally ARC. Before ARC, "weak" didn't exist yet.
I'm trying to make an NSMutableArray usable in multiple classes. I'm having an issue with defining and using a custom setter, for some reason, even though I call my setter, it is never executed (I have an NSLog set up in the method). Here is all of the relevant code:
AppDelegate.h
#interface TouchTrackerAppDelegate : NSObject <UIApplicationDelegate> {
NSMutableArray *completeLines;
}
#property (nonatomic, retain, setter = setCompleteLines:, getter = getCompleteLines) NSMutableArray *completeLines;
-(NSMutableArray*) getCompleteLines;
-(void) setCompleteLines:(NSMutableArray *) newLines;
AppDelegate.m
#implementation TouchTrackerAppDelegate
-(NSMutableArray*) getCompleteLines {
return self.completeLines;
}
-(void) setCompleteLines:(NSMutableArray *)newLines {
NSLog(#"gets here");
if (completeLines != newLines) {
[completeLines release];
completeLines = [newLines retain];
}
NSLog(#"completeLines global count: %i",[completeLines count]);
}
View.h
#import "TouchTrackerAppDelegate.h"
#interface TouchDrawView : UIView {
NSMutableDictionary *linesInProcess;
NSMutableArray *completeLines;
TouchTrackerAppDelegate *navigationDelegate;
}
#end
View.m*
#import "TouchTrackerAppDelegate.h"
- (id)initWithCoder:(NSCoder *)c
{
[super initWithCoder:c];
linesInProcess = [[NSMutableDictionary alloc] init];
completeLines = [[NSMutableArray alloc] init];
return self;
}
- (void)viewDidLoad {
navigationDelegate = (TouchTrackerAppDelegate *)[[UIApplication sharedApplication] delegate];
}
-(void)endTouches:(NSSet *)touches
{
if([EditModeSingleton isEditMode]){
for(UITouch *t in touches){
NSValue *key = [NSValue valueWithPointer:t];
Line *line = [linesInProcess objectForKey:key];
if(line){
[completeLines addObject:line];
[linesInProcess removeObjectForKey:key];
[navigationDelegate setCompleteLines:completeLines];
NSLog(#"completeLines count: %i", [completeLines count]);
}
}
[self setNeedsDisplay];
}
else {NSLog(#"in Play mode");}
}
The problem arises in my View.m when I call '[navigationDelegate setCompleteLines:completeLines];'. As far as I can tell, this never executes. I'm also not sure if my setter method is correct in the way I'm trying to pass the array from my view to the app delegate for use in other classes. If there is a better way of doing that, I'd appreciate some help.
Thank you!
If you're not entering that function, there's really only one solid possibility:
navigationDelegate is nil. Verify this by logging or asserting it just before sending the message to it in endTouches and then figure out why.
Cnage:
[linesInProcess removeObjectForKey:key];
[navigationDelegate setCompleteLines:completeLines];
To:
[linesInProcess removeObjectForKey:key];
NSAssert(navigationDelegate != nil, #"navigationDelegate is nil");
[navigationDelegate setCompleteLines:completeLines];
For future reference/help (and to answer your question in comments) -
Breakpoint basics in brief:
Set breakpoints at or before the line where you suspect your code breaks/fails/behaves-unexpectedly. Run your program in debug...
If the breakpoint gets hit: Examine both the call-stack and variable-values in the various Debugging panes in Xcode for clues.
Or if the breakpoint is never hit: Go back up a step in your function calls and set a breakpoint there.
If nothing else, breakpoints can narrow your issue down by process of elimination and help you ask better questions that get answered faster. =)
Although StackOverflow helped you track down this problem pretty fast, you can save yourself a lot of time and frustration in the future if you make use of breakpoints.
In this case, setting a breakpoint at or before the line: [navigationDelegate setCompleteLines:completeLines]; would have revealed navigationDelegate was nil. Then you repeat: set a breakpoint at or before navigationDelegate is assigned and re-run it. When this breakpoint didn't get hit, you would then realize your problem is something other than your setter! =)
You might still have had to ask "why isn't viewDidLoad being called?" but with part of the confusion already solved by you, your answer would have arrived much faster! Hope that helps you in the future~
I've just run into blocks and I think they are just what I'm looking for, except for one thing: is it possible to call a method [self methodName] from within a block?
This is what I'm trying to do:
-(void)someFunction{
Fader* fader = [[Fader alloc]init];
void (^tempFunction)(void) = ^ {
[self changeWindow:game];
//changeWindow function is located in superclass
};
[fader setFunction:tempFunction];
}
I've been searching for a couple of days and I can't find any evidence that this is possible.
Is this at all possible, or am I trying to use blocks for something they aren't meant for?
The reason I'm using blocks is that I've created a Fader class, and I want to store a block for it to execute when it finishes fading out.
Thank you
EDIT:
Okay, I added in the suggestion, but I'm still getting an EXC_BAD_ACCESS error...
-(void)someFunction{
Fader* fader = [[Fader alloc]init];
__block MyScreen* me = self;
void (^tempFunction)(void) = ^ {
[me changeWindow:game];
//changeWindow function is located in superclass
};
[fader setFunction:tempFunction];
[fader release];
}
Maybe I'm not allowed to give fader the function...?
Yes, you can do this.
Note, however, that the block will retain self. If you end up storing this block in an ivar, you could easily create a retain cycle, which means neither would ever get deallocated.
To get around this, you can do:
- (void) someMethodWithAParameter:(id)aParameter {
__block MySelfType *blocksafeSelf = self;
void (^tempFunction)(void) = ^ {
[blocksafeSelf changeWindow:game];
};
[self doSomethingWithBlock:tempFunction];
}
The __block keyword means (among other things) that the referenced object will not be retained.
The accepted answer is outdated. Using __block in that case can cause errors!
To avoid this problem, it’s best practice to capture a weak reference to self, like this:
- (void)configureBlock {
XYZBlockKeeper * __weak weakSelf = self;
self.block = ^{
[weakSelf doSomething]; // capture the weak reference
// to avoid the reference cycle
}
}
Please, look at Apple Documentation - Avoid Strong Reference Cycles when Capturing self
for more details.
__block CURRENTViewController *blocksafeSelf = self;
[homeHelper setRestAsCheckIn:strRestId :^(NSObject *temp) {
[blocksafeSelf YOURMETHOD:params];
}];
Is it possible to call a method [self methodName] from within a block?
Yes, why not. If your tempFunction is an instance method, you can do it. The called method should be accessible is the only restriction.
Consider this (which I think is the best practice)
#implementaion ViewController
- (void) viewDidLoad {
__weak typeof(self) wself = self;
[xxx doSomethingUsingBlock: ^{
__strong typeof(wself) self = wself;
[self anotherMessage];
}];
}
#end
Moreover, You can define wrapper macros.
#define MakeWeakSelf __weak typeof(self) wself = self
#define MakeStrongSelf __strong typeof(wself) self = wself
I wonder whether you [fader setFunction:tempFunction]; then is synchronous or asynchronous.
blocks push onto stack.so in MRR,if you don't retain it,it will pop off.
-(void)someFunction{
Fader* fader = [[Fader alloc]init];
void (^tempFunction)(void) = ^ {
[self changeWindow:game];
//changeWindow function is located in superclass
};
[fader setFunction:tempFunction];
//if the tempFunction execute there will be right.
}//there the tempFunction pop off
//....some thing go on
//execute the tempFunction will go wrong.
I have a class derived from NSThread:
#interface FSEventMonitorThread : NSThread {
FSEventStreamRef m_fseStreamRef;
CFRunLoopRef m_runLoop;
}
- (id) initWithStream:
(FSEventStreamRef)fseStreamRef;
- (void) dealloc;
- (void) main;
#end
#implementation FSEventMonitorThread
- (id) initWithStream:
(FSEventStreamRef)fseStreamRef
{
if ( self = [super init] )
m_fseStreamRef = fseStreamRef;
return self;
}
- (void) dealloc
{
CFRunLoopStop( m_runLoop );
FSEventStreamStop( m_fseStreamRef );
[super dealloc];
}
- (void) main
{
m_runLoop = CFRunLoopGetCurrent();
FSEventStreamScheduleWithRunLoop(
m_fseStreamRef, m_runLoop, kCFRunLoopDefaultMode
);
FSEventStreamStart( m_fseStreamRef );
CFRunLoopRun();
}
#end
Elsewhere (inside a C++ function), I create an instance:
m_thread = [[FSEventMonitorThread alloc] initWithStream:m_fseStreamRef];
My understanding is that the retain-count should now be 1.
In another C++ function, I want to stop and deallocate the thread:
[m_thread release];
Yet the dealloc method is not called. If I instead do:
[m_thread release];
[m_thread release];
then dealloc is called which implies the retain-count was 2. But how did it get to be 2?
Note that the documentation for NSThread only mentions retaining when using detachNewThreadSelector:toTarget:withObject:.
The framework itself keeps ownership of the thread. This is necessary so that the thread object doesn't go away while the main method is executing. If you want to stop a thread, you are doing it the wrong way. You must provide some sort of inter-thread communication to signal the thread's main method that it should stop whatever it is doing, clean up, and exit. Once that happens, relinquishing your ownership of the thread will cause the thread to dealloc. You should never simply over-release something to get it to "go away". If you are doing that, you are almost certainly not using the provided objects the way they are meant to be used, as in this case.
A very simple example to cancel your thread might be:
- (void)finishThread
{
if( [NSThread currentThread] != self ) // dispatch this message to ourself
[self performSelector:#selector(finishThread) onThread:self withObject:nil waitUntilDone:NO];
else
CFRunLoopStop(CFRunLoopGetCurrent());
}
I'm having problems starting & stopping NSTimers. The docs say that a timer is stopped by [timer invalidate];
I have a timer object declared as such
.h
NSTimer *incrementTimer;
#property (nonatomic, retain) NSTimer *incrementTimer;
.m
#synthesize incrementTimer;
-(void)dealloc {
[incrementTimer release];
[super dealloc];
}
-The usual.
When it's needed, my method does the following:
-(void)setGenCount {
if(!condition1 && condition2) {
incrementTimer = [NSTimer scheduledTimerWithTimeInterval: 2.0
target: self
selector:#selector(incrementBatteryVoltage:)
userInfo: nil
repeats: YES];
}
}
Everything above works fine. However, once that timer does it's job, I want it to invalidate itself. I invalidate the timer because there is an equal decrement method that could be called and would fight against the incrementTimer if it was still active. (Previously, I noticed that my two timers, if active, were acting on the same ivar by increasing & decreasing the value (a sort of fight)... without crashing) The selector called works as follows:
-(void)incrementBatteryVoltage:(NSTimer *)timer {
if(battVoltage < 24.0) {
generatorDisplay.battVoltage += 0.1;
}
if(battery1Voltage == 24.0) {
[timer invalidate];
}
}
I have an equal method that Decrements the battery count. (previously mentioned)
Due to my program design: the interface simulates a voltage display. When the "machine" is turned off, I want all the timers invalidated, regardless of what any voltage value is. I'm doing this by checking to see if the timer is valid.
-(void)deEnergizeDisplays {
if([decrementTimer isValid]) {
[decrementTimer invalidate];
decrementTimer = nil;
}
if([incrementTimer isValid]) {
[incrementTimer invalidate];
incrementTimer = nil;
}
I'm getting numerous "BAD_ACCESS" crashes. The erroneous line call is always pointing toward my [timer isValid] call. It seems that if the timer is invalidated... the pointer
doesn't exist either. I know that the [timer invalidate] message disables the timer and then it is removed from the run loop and then it is released. And my understanding is: it is an autoreleased object per it's naming covention.
My thought are: If I'm sending a retain message, shouldn't the reference still exist? I've tried several combinations, taking away:
timer = nil;
or even instead of:
if([timer isValid])
I tried :
if([timer != nil])
and:
if(timer)
I always get the same crash. Thanks for any help on starting & stopping NSTimers.
UPDATE: See Darren's answer. The problem is that you are not using your property accessor when setting the timers. Instead of:
incrementTimer = [NSTimer ...
You should have:
self.incrementTimer = [NSTimer ...
The self.propertyName = ... syntax will call your accessor method, and thereby automatically retain the object that you send to it (since your property is set up as retain). Simply calling propertyName = ... does not use the property accessor. You are simply changing the value of your ivar directly.
UPDATE #2: After an enlightening conversation with Peter Hosey (see comments), I have removed my earlier suggestion to "never retain or release" your timer object. I have also completely re-written my earlier code because I think the following is a better approach:
Controller.h:
NSTimer *voltageTimer;
float targetBatteryVoltage;
...
#property (nonatomic, retain) NSTimer *voltageTimer;
Controller.m:
#implementation Controller
#synthesize voltageTimer;
- (void)stopVoltageTimer {
[voltageTimer invalidate];
self.voltageTimer = nil;
}
- (void)setTargetBatteryVoltage:(float)target {
[voltageTimer invalidate];
targetBatteryVoltage = target;
self.voltageTimer = [NSTimer scheduledTimerWithTimeInterval: 2.0
target: self
selector: #selector(updateBatteryVoltage:)
userInfo: nil
repeats: YES];
}
- (void)updateBatteryVoltage:(NSTimer *)timer {
const float increment = 0.1;
if (abs(battVoltage - targetBatteryVoltage) < increment) {
[timer invalidate];
}
else if (battVoltage < targetBatteryVoltage) {
generatorDisplay.battVoltage += increment;
}
else if (battVoltage > targetBatteryVoltage) {
generatorDisplay.battVoltage -= increment;
}
}
Now, you can simply set a target battery voltage, and the timer magic will happen behind the scenes:
[self setTargetBatteryVoltage:24.0];
Your power-off method would look as follows:
- (void)deEnergizeDisplays {
[self stopVoltageTimer];
}
You need to retain the value assigned to incrementTimer in setGenCount. You can do this automatically by using your synthesized property, which is accessed via self.:
self.incrementTimer = [NSTimer scheduledTimerWithTimeInterval: ...