Hello I am pretty new to programming but I have been following a few tutorials in Objective C. I just came across a problem in a Exception Handling tutorial and well, my code didn't work the same way.
First of all this is my code in main:
#import < Foundation/Foundation.h>
#import "Numz.h"
int main(int argc, const char * argv[]){
#autoreleasepool {
Numz *n = [[Numz alloc]init];
#try {
[n thisisgoingtogetanerror] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< error on this line
}
#catch (NSException *e) {
NSLog(#"you got an error in your program");
}
NSLog(#"this is code aftr the error");
}
return 0;
}
The error above says
no visible #interface for 'Numz' declares the selector
'thisisgoingtogetanerror'
My interface and implementation are created but have no variables or methods created inside, but isn't that why I need to handle the error in the first place?
Also, I can't get any kind of console view either, the build just fails and points me at that error.
It might be some settings in xcode 4.6 that I need to change but I can't get the code to run and handle the error. I have looked online and can't find any answers.
Any help would be great.
The compiler is complaining because you are calling a method that it has not seen a declaration of ever.
Change it to (assuming Numz is not a subclass of NSArray nor implements the count method): [n count];.
Note that you should never use exceptions for flow control. That is, you should not #throw an exception and then use #catch to process the exception and continue execution. Exceptions in iOS/Cocoa are only used to indicate unrecoverable errors.
Try this:
#interface NSObject(Badness)
- (void)methodBadness;
#end
Then call that method in your code. Compiler shouldn't warn, runtime should #throw.
Exception handling is used for errors/exceptions at runtime. But the error you get occurs at compile time
You can cause a runtime error through something like this:
#interface RuntimeError : NSObject
+ (void)cause;
#end
#implementation RuntimeError
+ (void)cause {
NSAssert(NO, #"This is a runtime error caused through a assertion failure")
}
#end
// Call it with
// [RuntimeError cause]
// inside the #try-Block
Related
If I have methods like:
- (BOOL)isValidRow:(NSDictionary*)contentVersionRow
do we really have to continually check like this at the beginning of the method
if(![contentVersionRow isKindOfClass:[NSDictionary class]]) {
// Handle unusual situation - probably return NO in this case
}
to really implement proper type-safety inside Objective-C methods? Because in theory the parameter is not guaranteed to point to an NSDictionary object, is this correct?
EDIT: So answers so far seem to indicate we should not check for this, but then what is the difference between checking for this and checking for nil parameter, which I assume we should do? Or should we not check for nil either, if it's not normally expected? Both cases cover the situation of a misbehaving caller.
Just like in C you are dealing with pointers in Objective-C. So saying NSDictionary * simply means "here's a pointer to a memory address that contains an instance of NSDictionary".
Example:
#import <Foundation/Foundation.h>
#interface Test : NSObject
- (void)useDictionary:(NSDictionary *)dictionary;
#end
#implementation Test
- (void)useDictionary:(NSDictionary *)dictionary
{
NSLog(#"Keys: %#", [dictionary allKeys]);
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
Test *test = [[Test alloc] init];
// 1: This works fine
[test useDictionary:#{#"key": #"value"}];
// 2: This will cause a compiler warning (or error depending on the options passed to the compiler)
[test useDictionary:#"not a dictionary"];
// 3: This will compile without any warnings
[test useDictionary:(NSDictionary *)#"not a dictionary"];
}
}
The 2nd and 3rd examples will cause the program to crash at runtime. So if you want to pass incorrect things to methods, you can. Usually Xcode will warn you if you have a type-mismatch.
Update about nil-checking: If it's an API-misuse to pass nil to your method, then throw an exception. That's what exceptions are for in Objective-C: to catch programming mistakes, not to handle expected runtime issues (like an unreachable network). If your method can just silently fail if nil is passed in or handle it in a sensible way, then do that instead. For example if you have a method addValue:(NSNumber *)number that adds the given value to a sum then it wouldn't be a big deal if someone called it with nil: Just don't add anything :)
Yes, but you shouldn’t.
Obj-C is a dynamic language, so it is up to each object to determine if it responds to a certain method. It is bad style to check the class of an object.
Instead, if you want to check that an object supports a selector you should use -respondsToSelector:, but only if you handle objects not responding to that selector.
Environment: Mac OS 10.8.5, XCode 5.1.1
Problem: Crash in obj_msgsend on addObject message to a NSMutableArray
Disclaimer: I'm new to Objective-C, so this could an obvious mistake. But it's mysterious.
Details:
I've been able to prune the problem down to a small test case (thankfully), though the exact manifestation of the problem is different from the full application.
Here's the #interface:
#interface ObjCQueue : NSObject
+ (void) push: (NSString *)calEvent;
+ (NSString *) pop;
#end
Here's the Objective-C class implementation.
#import <Foundation/Foundation.h>
#include "ObjcQueue.h"
NSMutableArray *qArray;
#implementation ObjCQueue
{
}
+ (void) init
{
qArray = [[NSMutableArray alloc] init];
// NSLog(#"(init)qArray class is: %#\n", NSStringFromClass([qArray class]));
}
+ (void) push:(NSString *)calEvent
{
[qArray addObject:calEvent];
}
+ (NSString *) pop
{
// This will return nil if there's no first object
NSString *retEvent = [qArray objectAtIndex:0];
// Don't delete the front of the queue if nothing is there
if (retEvent != nil)
[qArray removeObjectAtIndex:0];
return retEvent;
}
#end
and main.m does this:
int main(int argc, const char * argv[])
{
#autoreleasepool {
[ObjCQueue init];
[ObjCQueue push:#"Pushed thing"];
NSLog(#"Popped: %#\n", [ObjCQueue pop]);
}
return 0;
}
For the moment, let's ignore the possibility that how I'm doing this is totally wrong (we'll get back to that).
If I run this code as-is, I get a crash in objc_msgSend called by the addObject message sent from [ObjCQueue push:]
The mystery part is, if I uncomment the NSLog call in [ObjCQueue init] everything runs just fine.
In the larger application, I see a different issue. The failure also occurred in the push method, except the run-time error I got said that addObject was an invalid selector. When I check the type of qArray in that case, it has a type of NSDictionary (that's from memory, it wasn't spelled exactly that way) instead of NSMutableArray. Also, in the larger application, adding the NSLog call in the init method makes everything run smoothly.
In this smaller example, the type of qArray always appears to be NSMutableArray.
In other answers to similar questions, the implication is that the object corresponding to qArray is getting overwritten, and/or released prematurely. I don't see how that could happen here, since it's global, and ObjCQueue only has class methods and no instance of it is created. [ObjCQueue init] is only called once.
One other bit of data: In this smaller case, qArray gets displayed differently depending where (in the debugger) it's displayed.
In init, in the case where it crashes, immediately after qArray gets its value, the debugger shows:
Printing description of qArray:
<__NSArrayM 0x10010a680>(
)
But in push, just before the addObject method is called, the debugger shows:
Printing description of qArray:
(NSMutableArray *) qArray = 0x000000010010a680
The value is the same, but the type is kinda sorta different (maybe). In the case with no crash, the display is identical in both cases (they're both the same as the first display)
This may not be the best way (or it may be a blatantly wrong way) to initialize qArray, and I can accept that. But why would the behavior change with the addition of the NSLog call?
Any help/insights will be appreciated.
-Eric
P.S. Here's the XCode project: Bug Test
The problem is because ARC is releasing qArray before you called push so you're calling on an object that is already released. A good solution to this problem would be to either change your class to an actual instance, or create a singleton so that ARC knows to retain the array rather than just releasing it right after you init.
This question already has answers here:
"Thread 1: stopped at breakpoint" error when initializing an NSURL object
(3 answers)
Closed 8 years ago.
I am unable to send a message to an Objective C method with multiple parameters. The method has two parameters, a NSString object and a Boolean variable. I can successfully make the call when I edit my method code so it only has either one of these parameters, but not both. I don't get any compile errors. When I run the program, the program stops and I get a breakpoint at the method call, but the XCode debugger doesn't give any additional info on why it stopped there. I can then choose to continue running the program and it performs as expected. I currently am calling the method from within another method of the same class. I have tried calling the method directly from main, but have the same issue. I have tried numerous changes within the saySomething method, including just commenting out the entire contents of the method, but my program still stops at the method call. My interface and implementation files are below. Thanks for any help you can provide!
Edit: I have also added the code from main as requested.
#interface XYZPerson : NSObject
- (void) sayHello;
- (void) saySomething:(NSString *)whatToSay loudly:(Boolean)toYell;
#end
#implementation XYZPerson
- (void)sayHello
{
NSString *greeting = #"Hello, World!";
[self saySomething:greeting loudly:YES];
}
- (void)saySomething:(NSString *)whatToSay loudly:(Boolean)toYell
{
NSString *whatToSayEdited = whatToSay;
if (toYell == YES) {
whatToSayEdited = [whatToSay uppercaseString];
}
NSLog(#"%#", whatToSayEdited);
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
// insert code here...
XYZPerson *somePerson = [[XYZPerson alloc] init];
[somePerson sayHello];
}
return 0;
}
Sounds like you have a breakpoint set at the
if (toYell == YES) {
whatToSayEdited = [whatToSay uppercaseString];
}
block of code, that would explain why without the second parameter it runs smoothly, but stops when you set both parameters.
if it continues to run properly after you tell it to continue it is not an error but really just a breakpoint. Look on the left side of your editor where the line numbers are. Breakpoints appear as blue blocky arrows.
I need to use Objective-C++ code in inherited C++ class which works with video recording from iPhone camera (getting CMSampleBufferRef through an other native-objective-c class Wrapper with CMSampleBufferDelegate).
The AVCaptureVideoOutput that i have works in its own dispatch_queue_t callbackQueue, so, when i want to get the last frame from my Wrapper class, I need to lock the callbackQueue to make it wait till the copying will be done.
As i know, it's done with dispatch_sync, syncing the captureOutput.callbackQueue. But i can't get this code working:
// .mm
frame_t MyCppClass::getLastFrame()
{
dispatch_sync(pCaptureVideoDataOutput.sampleBufferCallbackQueue, ^{ // error: no matching function for call to 'dispatch_sync'
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(wrapperInstance->currentBuffer);
CVPixelBufferLockBaseAddress(imageBuffer,0);
// doing copying frame data from buffer...
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
}); // error: control may reach end of non-void block
return frame;
}
// .h
#interface Wrapper : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate> {
CMSampleBufferRef currentBuffer;
}
#end
// .mm
#implementation Wrapper
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
// doing copying to currentBuffer
}
#end
EDIT:
When i changed to
dispatch_sync(pCaptureVideoDataOutput.sampleBufferCallbackQueue, (dispatch_block_t)^{
it fixed the first error, but the second is still here..
Got stuck with this.. any help is appreciated!
I figured it out!
I've got some emergency return statements inside the block. I thought that it will return the function, but it returns the block... so compiler was right.
The error:
error: no matching function for call to 'dispatch_sync'
indicates that the function prototype may not be visible. Make sure you are including the header for libdispatch in your .mm file...
#include <dispatch/dispatch.h>
The second error:
error: control may reach end of non-void block
is because your function is declared to return a frame_t but it has no return statement.
I have this call in UIViewController-inheritor class context:
+ (void) smthPressed: (id) caller
{
// some code here
// ...
startTimers();
}
startTimers declared as:
inline void startTimers()
{
NSString * x = #""; // falls here with EXC_BAD_INSTRUCTION
// some other codes here
}
What the HELL is going on?
P.S.:
inline void startTimers()
{
int x = 0;
int y = 0; // EXC_BAD_INSTRUCTION here. Stack couldn't end there!
// ...
P.P.S.:
Documentation says: "For most non-memory access exceptions (for example, EXC_BAD_INSTRUCTION ...)", so it is NOT mem-access fault.
P.P.P.S.: arch is Standart (armv6 armv7). Nothing changes if I set Optimized (armv7).
Perhaps you have corrupted your stack accidentally. Does it occur when you place the startTimers() code elsewhere in your program?
Try using NSZombieEnabled and the static analyser to look for other places in your code you might be making memory-management errors that could lead to a write to a stack variable being invalid (overflowing arrays on the stack, bad pointers, etc).
You could also try switching compilers, if that option is available to you, in the extremely rare case that you hit a complier bug.
I think there is compiler issue here. Now, 6 years since your raising the issue, if I try to get your original code to compile it fails. It's down to the static keyword. The following code compiles and runs ok:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[ViewController smthPressed:self];
}
// Without the "static" keyword compile fails
static inline void fakeStartTimers() {
int x = 0;
int y = 0;
printf("x and y are %d %d", x, y);
}
+ (void)smthPressed:(id) caller
{
fakeStartTimers();
}
#end
This is with the compiler
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang --version
Apple LLVM version 9.1.0 (clang-902.0.39.1)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin