Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

BoxerRobban472

macrumors member
Original poster
Sep 12, 2013
66
1
Gothenburg, Sweden
Hello!

I have written a command-line tool that allows you to search for a property of a object (I created an custom class that allowed you to set the name of the file and the pathway to the file) and, if the search word matches the property, the file will open. When I did this with about 10 files it works as I want it to, but if I have around 60 files, I get a Thread 1: Signal SIGABRT error. The StackOverflow-community helped me figure out that this was because a certain value is equal to nil. I have not gotten any further answer on how to fix this on StackOverflow so I thought I would see if anyone here could help me!

Here is my code:

SMADoc.h (my custom class)
Code:
#import <Foundation/Foundation.h>

@interfaceSMADoc : NSObject

@property(nonatomic)NSNumber*docNumber
@property(nonatomic)NSString*urlToDoc;

@end

main.m
Code:
#import <Foundation/Foundation.h>
#import "SMADoc.h"
#include <readline/readline.h>
@import AppKit;

void *documentSearch() {
SMADoc *one = [[SMADoc alloc] init];
[one setdocNumber:@(17800)];
[one setUrlToDoc:@"/Users/Docs/docPath1.pdf"];

SMADoc *two = [[SMADoc alloc] init];
[two setdocNumber:@(11632)];
[two setUrlToDoc:@"/Users/Docs/docPath2.pdf"];

SMADoc *three = [[SMADoc alloc] init];
[three setdocNumber:@(17583)];
[three setUrlToDoc:@"/Users/Docs/docPath3.pdf"];

SMADoc *four = [[SMADoc alloc] init];
[four setdocNumber:@(14351)];
[four setUrlToDoc:@"/Users/Docs/docPath4.pdf"];

SMADoc *five = [[SMADoc alloc] init];
[five setdocNumber:@(11628)];
[five setUrlToDoc:@"/Users/Docs/docPath5.pdf"];

NSMutableArray *docs = [[NSMutableArray alloc] initWithObjects:one, two, three, four, five, nil];

int i = 0;

NSLog(@"Enter what you want to search for: ");
const char *searchC = readline(NULL);
int number = atoi(searchC);
NSNumber *sNumber = [NSNumber numberWithInteger:number];

for (SMADoc *nSearch in docs) {
    if ([sNumber isEqualToNumber:[nSearch docNumber]]) {
        NSLog(@"Opening document...");
        [[NSWorkspace sharedWorkspace] openFile:[nSearch urlToDoc]];
    }
    if (![sNumber isEqualToNumber:[nSearch docNumber]]) {
        i++;
    }
}
if (i == [docs count]) {
    NSLog(@"A match could not be found, please check your spelling");
}
free(documentSearch());
documentSearch();

return 0;
}

int main(int argc, const char * argv[]) {
@autoreleasepool {
    NSLog(@"message");
    documentSearch();
}
return 0;
}

This is the line that gives the SIGABRT-error:
Code:
if ([sNumber isEqualToNumber:[nSearch docNumber]]) {

And this is the output in the console:
Code:
2015-07-14 22:05:24.173 LIX4[512:11135] message
2015-07-14 22:05:24.175 LIX4[512:11135] Enter what you want to search for:
1717

2015-07-14 22:05:25.843 LIX4[512:11135] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber compare:]: nil argument'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff88eed03c __exceptionPreprocess + 172
    1   libobjc.A.dylib                     0x00007fff8c5cf76e objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff88eeceed +[NSException raise:format:] + 205
    3   CoreFoundation                      0x00007fff88dea031 -[__NSCFNumber compare:] + 81
    4   CoreFoundation                      0x00007fff88de9fc8 -[__NSCFNumber isEqualToNumber:] + 24
    5   LIX4                                0x0000000100004a3a documentSearch + 14490
    6   LIX4                                0x0000000100005355 main + 53
    7   libdyld.dylib                       0x00007fff8d1ae5c9 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

The StackOverflow-community helped me narrow down the problem to that it must be the
Code:
[nSearch docNumber]
that is nil but after that I'm stuck...

I think that this is relevant in the error-output:
Code:
'NSInvalidArgumentException', reason: '-[__NSCFNumber compare:]: nil argument'

I tried googling this and what I got for answer is that the two variables/objects being compared must be the same type, but both
Code:
sNumber
and
Code:
[nSearch docNumber]
are NSNumbers so I don't see how that could apply here...

And this is were I am stuck... Any help would be greatly appreciated! Here is the link to the StackOverflow-post if anyone is interested:http://stackoverflow.com/questions/...ith-too-many-files-in-array/31320986#31320986

Thanks in advance!
 
Last edited:

mfram

Contributor
Jan 23, 2010
1,333
380
San Diego, CA USA
This is exactly what a debugger is designed for. Put a breakpoint on the line "
if ([sNumber isEqualToNumber:[nSearch docNumber]])" and then start examining variables. You should see very quickly what your problem is when examining the variables in the debugger and seeing that the objects look like.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,885
8,694
A sea of green
A few things I noticed:

1. Your "SMADoc.h" file is missing some spaces.
I don't see how it could compile as posted. Notably:
Code:
@interfaceSMADoc:NSObject
This needs a space between interface and SMADoc. Something went wrong with your paste, because the code you posted at StackOverflow looks fine.

2. I don't understand why you're using NSNumber instead of a simple primitive type like long or int.
This isn't a bug, per se, it just seems like an impractical use of NSNumber.

3. This code makes no sense. It's almost certainly wrong:
Code:
free(documentSearch());
documentSearch();

return 0;
Please explain what you intend to accomplish with this code. I can't discern any rational intent here, so I need a plain language explanation of what you expect it to do.

Here's what's wrong:
a) There are two recursive calls to documentSearch() here, neither of which makes any sense. Why the recursion?

"Recursion" means the documentSearch() function calls itself, which then reaches the same point of needing to call itself before calling free(), so it then calls itself, reaches the same point, calls itself again, and so on until you run out of stack space.

b) Even without recursion, a call to free() makes no sense. You haven't malloc'ed or calloc'ed anything, so calling free() is wrong. Why are you calling free()?

c) The function returns 0, which would then be passed to free() (if a call to free() made sense, and the recursion somehow ended). But free() should not be called with a NULL pointer, which is what returning 0 means here. Why are you returning 0?
 
  • Like
Reactions: BoxerRobban472

BoxerRobban472

macrumors member
Original poster
Sep 12, 2013
66
1
Gothenburg, Sweden
This is exactly what a debugger is designed for. Put a breakpoint on the line "
if ([sNumber isEqualToNumber:[nSearch docNumber]])" and then start examining variables. You should see very quickly what your problem is when examining the variables in the debugger and seeing that the objects look like.

Thank you so much for your answer, this solved my problem! I checked the debugger several times before posting on StackOverflow (and here) but couldn't find anything wrong (I thought). I decided to check one more time though, by opening up both versions of my program; The one with 60 files that kept crashing and the one with five files (the code I posted here) and set a breakpoint at
Code:
if ([sNumber isEqualToNumber:[nSearch docNumber]])
in both versions and then examining the variables as @mfram suggested and sure enough, I found something! I turned out that the value of the
Code:
sNumber
variable, which is what the user puts in, sometimes got stored in a
Code:
double
instead of a
Code:
int
and this was the problem! I solved this by using the variable
Code:
number
instead of
Code:
sNumber
(since that already was a int) replacing this code:

Code:
if ([sNumber isEqualToNumber:[nSearch docNumber]]) {

        [...]

    if (![sNumber isEqualToNumber:[nSearch docNumber]]) {

with this:

Code:
if (number == [[nSearch docNumber] intValue]) {

        [...]

   
(!(number == [[nSearch docNumber] intValue])) {

And that solved the problem!
 

BoxerRobban472

macrumors member
Original poster
Sep 12, 2013
66
1
Gothenburg, Sweden
A few things I noticed:

1. Your "SMADoc.h" file is missing some spaces.
I don't see how it could compile as posted. Notably:
Code:
@interfaceSMADoc:NSObject
This needs a space between interface and SMADoc. Something went wrong with your paste, because the code you posted at StackOverflow looks fine.

2. I don't understand why you're using NSNumber instead of a simple primitive type like long or int.
This isn't a bug, per se, it just seems like an impractical use of NSNumber.

3. This code makes no sense. It's almost certainly wrong:
Code:
free(documentSearch());
documentSearch();

return 0;
Please explain what you intend to accomplish with this code. I can't discern any rational intent here, so I need a plain language explanation of what you expect it to do.

Here's what's wrong:
a) There are two recursive calls to documentSearch() here, neither of which makes any sense. Why the recursion?

"Recursion" means the documentSearch() function calls itself, which then reaches the same point of needing to call itself before calling free(), so it then calls itself, reaches the same point, calls itself again, and so on until you run out of stack space.

b) Even without recursion, a call to free() makes no sense. You haven't malloc'ed or calloc'ed anything, so calling free() is wrong. Why are you calling free()?

c) The function returns 0, which would then be passed to free() (if a call to free() made sense, and the recursion somehow ended). But free() should not be called with a NULL pointer, which is what returning 0 means here. Why are you returning 0?

Thank you very much fot your answer!

1. Yes, you're right, something went wrong when I pasted the code that's fixed!

2. Yep I realize that now in retrospective. But hey, now I learned something until next time!:)

3. My intentions with those two lines was first to deallocate all the variables in the function (and I thought deallocating the function that contained those variables would deallocate all the variables) and then run the function again. I thought that free() was for deallocating functions/variables etc. but I'm not very experienced with programming yet and regarding your post it seems that free() won't deallocate functions the way I described it above... Do you have a suggestion on how that could be done? Would the best option be to just deallocate the variables one by one? (and the reason I wrote the 'return 0' was because Xcode was complaining that this didn't exist for some reason. This was in the beginning of the development of the program so it might be better to not include it know(?))

Again, thank you for your input!
 

chown33

Moderator
Staff member
Aug 9, 2009
10,885
8,694
A sea of green
3. My intentions with those two lines was first to deallocate all the variables in the function (and I thought deallocating the function that contained those variables would deallocate all the variables) and then run the function again. I thought that free() was for deallocating functions/variables etc. but I'm not very experienced with programming yet and regarding your post it seems that free() won't deallocate functions the way I described it above... Do you have a suggestion on how that could be done? Would the best option be to just deallocate the variables one by one? (and the reason I wrote the 'return 0' was because Xcode was complaining that this didn't exist for some reason. This was in the beginning of the development of the program so it might be better to not include it know(?))

Again, thank you for your input!
You can't just start throwing things into programs you don't understand. Well, you can, but you shouldn't expect them to work.

Why did you think free() was for deallocating variables? If you read it somewhere, where was it? Please be specific: post the URL, or cite the book and page number.

The free() function has a specific purpose. If what you read was in regards to the readline() function you're using, then you should follow the examples for that function exactly.


You may or may not need to deallocate the Objective-C objects in the function. You didn't say what OS or Xcode version you're using. More recent versions have automatic reference counting (ARC), and you rarely need to deallocate any objects. In older versions you'd use either release or autorelease, depending on how the object was being used.

My guess is you're using a version with ARC, because of the @(n) notation you've used in a few places, but that's just a guess. I can't offer a more specific suggestion on deallocating without knowing what OS and Xcode you're using.


Functions aren't deallocated (at least not in Objective-C). They aren't even deallocatable. Again, if you thought this was necessary or desirable, please point to where you read this.


The likely reason Xcode complained about the return is because you declared your documentSearch() functions is returning a void *. That isn't the same as declaring it returning void. That is, if your function has nothing to return, it's this:
Code:
void documentSearch()
while the following means something else entirely:
Code:
void * documentSearch()
And if you don't know what it means for a function to return a value of a particular type, then you need to study up on functions.


I get the sense you're not following a structured course (book, tutorial, video, etc.) for learning programming, but are instead trying to paste things together somewhat haphazardly. This might work for simple things, or for a short time, but it won't work for long. You need to understand what the code is doing, what it's capable of doing (e.g. functions can't be deallocated), and what things actually mean.

I recommend that you follow a tutorial to completion, or read a book and do all the exercises completely. Come back to this programming problem later, and you'll be better equipped to solve it.

When I used to teach programming, I'd tell my students that whatever program they came into the class wanting to write, they should put it on hold until after they'd written 10 other simpler programs. The students who had big plans and thought they could start right away were resistant to this, until they actually realized how little they understood about programming. In other words, once they realized the true scale and skills needed for what they wanted to make, they recognized that practicing on smaller simpler programs first was the proper path. A good book or tutorial series is a structured pathway through those smaller simpler programs, presenting both principles and practice.

Underestimating the size of a problem is common for the inexperienced. Even for the experienced, estimating scale and difficulty can be wrong by a factor of 2.
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
So let me summarize: The code that you posted didn't compile, therefore it couldn't crash. You probably had some code that looked similar to the code that you posted, and also didn't crash. And you had a third bit of code, which _did_ crash.

Did it occur to you that it's hard to find a bug in code that we don't even see? Here's a rule: If there's a bug in your code, and you can't find it, then something in your code doesn't do what you think it does, and you don't know which bit in the code that is. Any assumptions you make about what is wrong in your code are invalid, because you don't know where the bug is. So post the code that has the bug, and not some code that you _think_ has the bug. Even worse, you posted code that _didn't_ have the bug.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.