I am updating our iPhone app to iOs4 and I ran into an issue "Pass-by-argument in function call is undefined" in the code
for (i = 0; i < self.numberOfSegments; i++) {
[self setWidth:round(width[i]) forSegmentAtIndex:i];
}
Which is fair enough, width[i] hasn't been initialized. Updating the code (below) however gives me this new error, "Assigned value is garbage or undefined". Reading up on this I think that segWidth retains its value as garbage - is that correct and if so how do I clear it?
for (i = 0; i < self.numberOfSegments; i++) {
float segWidth = (float)width[i];
[self setWidth:round(segWidth) forSegmentAtIndex:i];
}
------------- EDIT ------------------
Thanks for the replies guys. More information as follows;
A genericised version of the method is shown below as someFunction. I have removed the ugly cast but still see the "Assigned Value is Garbage or undefined" logic error for the line segWidth = width[i];
I agree it appears the value width[i] doesn't have clear initialisation, I am unsure if it's my lack of understanding of basic Obj-c float types or if there is a logic flaw in my assignment syntax?
- (void)someFunction
{
unsigned int n = self.numberOfSegments;
float width[n];
for (i = 0; i < n; i++) {
width[i] = someFloatValue;
}
...
for (i = 0; i < self.numberOfSegments; i++) {
float segWidth = 0.0;
segWidth = width[i];
[self setWidth:round(segWidth) forSegmentAtIndex:i];
}
}
Definition of setWidth is:
- (void)setWidth:(CGFloat)width forSegmentAtIndex:(NSUInteger)segment; // set to 0.0 width to autosize. default is 0.0
I'm assuming that you are calling:
- (void)setWidth:(CGFloat)width forSegmentAtIndex:(NSUInteger)segment
And that Pass-by-argument in function call is undefined is actually the LLVM static analyzer error when you do Build and Analyze. (Both rather important data points -- passing along exactly what you were doing and exactly what the output was is quite helpful).
And you say that width[i] hasn't been initialized.
Your fix of adding float segWidth = (float)width[i] very much should cause the analyzer to complain with ** Assigned value is garbage or undefined**. You haven't actually set width[i] to anything. I would suggest filing a bug against the static analyzer, though, because that first error message is really quite thoroughly obtuse.
As Joshua also said, that cast is really weird, too. In general, in Objective-C you should very rarely have to use type casting and pretty much never use it on scalar types.
Consider the two loop counts:
for (i = 0; i < n; i++) {
...
}
for (i = 0; i < self.numberOfSegments; i++) {
...
}
The static analyzer doesn't know that n == self.numberOfSegments and, thus, must assume that the second loop could loop longer than the first. Now, you might say, "But I assigned n = self.numberOfSegments above?!"
You did, but that value could have changed between the first call and second call and, thus, the analyzer has correctly identified that you might be using an uninitialized value.
(Really, it should be saying that you might run off the end of the array, because that is the real risk).
Related
if ( $num_of_things > 1) {
my $max_element = $num_of_things -1;
for($max_element; $max_element >= 0; $max_element--) {
$value_array[$max_element] = $starting_hash{$key}[$max_element];
}
All of my variables not initialized in this code snippet have been initialized as part of the larger subroutine (which I don't want to put up due to length). I'm not sure where I'm getting the useless use of private variable in void context error in this code, my compiler is telling me it's the last line (with nothing but the closing brace "}"). All help is hugely appreciated as I've been staring at this loop for almost an hour with no idea what is wrong.
Move initialization (and declaration) of $max_element into for statement.
[see ooga comment ]
for( my $max_element=$num_of_things-1; $max_element>= 0; $max_element--) {
$value_array[$max_element] = $starting_hash{$key}[$max_element];
}
My app works perfectly on the debug version, but when I create a release version and install it on my iphone, double values mysteriously change value. I know this by looking at the logs.
double amountComplete;
double possibleTotal;
for (int i = 0; i<self.tasksArray.count; i++) {
Task *myTask = [self.tasksArray objectAtIndex:i];
possibleTotal = possibleTotal + [myTask.size doubleValue];
if (myTask.completed==[NSNumber numberWithInt:1]) {
amountComplete = amountComplete + [myTask.size doubleValue];
}
}
Amount possible ends up being a hige number such as 12312213.0000.
How do I fix this and why does it only happen on the release version?
You ignored the "variable amountComplete is used uninitialized" warnings. Change the declarations to
double amountComplete = 0;
double possibleTotal = 0;
(In debug mode, entirely by accident, these variables' storage locations happen to contain floating-point zeroes on entry to the loop. Remember, undefined behavior includes the possibility of everything appearing to work just fine.)
So I'm working on a simple calculator program to get used to cocoa and objective C. I've redone the whole thing multiple times and every time I finish coding, the first time i build it, it works fine, but every time after that the window wont launch and it gives me these errors:
2013-01-11 10:32:14.760 Visual Caluclator Fix[39892:403] *** Assertion failure in -[NSTextFieldCell _objectValue:forString:errorDescription:], /SourceCache/AppKit/AppKit-1138.47/AppKit.subproj/NSCell.m:1564
2013-01-11 10:32:14.762 Visual Caluclator Fix[39892:403] Ignoring exception raised in __-[NSPersistentUIManager restoreAllPersistentStateWithTalagentWindows:registeringAsReadyWhenDone:completionHandler:]_block_invoke_3: Invalid parameter not satisfying: aString != nil
I've concluded that the problem lies in my textEdited method, because when I comment the code inside of it out, the program has no issues running; however, I have no idea why this is, or why it would run the first time and not any subsequent times. When I put in an exception breakpoint, it points me to the one line in the updateUI method and the call to [self updateUI] in the textEdited method. The following code is the textEdited method and the other methods it references.(I'm fairly sure there's nothing wrong with the solve method because I used it in a command prompt calculator and it worked great. Also, I know this is a pretty convoluted way to program a calculator, with the strings and everything, but I was just trying to integrate the code I already had for the command prompt program into a cocoa program.)
In the AppDelegate class:
- (void)updateUI{
[self.calculationView setStringValue: self.calculation.calcString];//Exception breakpoint points here
}
- (IBAction)textEdited:(id)sender {
self.calculation.calcString = self.calculationView.stringValue;
[self.calculation solve];
[self updateUI];//Exception breakpoint points here
}
In the Calculation class:
- (NSString*)solve{
for (int i = 0; i < [self.calcString length]; i++) {
NSRange nextChar = NSMakeRange(i, 1);
if ([[self.calcString substringWithRange: nextChar] isEqualToString: #"*"]||
[[self.calcString substringWithRange: nextChar] isEqualToString: #"/"])
[self calcTerm: i];
}
for (int i = 0; i < [self.calcString length]; i++) {
NSRange nextChar = NSMakeRange(i, 1);
if ([[self.calcString substringWithRange: nextChar] isEqualToString: #"+"]||
[[self.calcString substringWithRange: nextChar] isEqualToString: #"-"])
[self calcTerm: i];
}
return self.calcString;
}
This might help with your problem:
http://www.raywenderlich.com/10505/my-app-crashed-now-what-part-2
The site explains how assertion errors work and demonstrate how you would fix an error like that.
It sounds to me like something in calcTerm: is setting calcString to nil. Thus, when you retrieve it later to set the field's string value to it, you end up setting the field's string value to nil, which it doesn't like.
You can check this by logging the value of calcString just before the end of solve. Then, start stringing up log statements and/or breakpoints in calcTerm: to find out how you're swapping out your string for nil.
I've been porting newlib to my very small kernel, and I'm stumped: whenever I include a function that references a system call, my program will page fault on execution. If I call a function that does not reference a system call, like rand(), nothing will go wrong.
Note: By include, I mean as long as the function, e.g. printf() or fopen(), is somewhere inside the program, even if it isn't called through main().
I've had this problem for quite some time now, and have no idea what could be causing this:
I've rebuilt newlib numerous times
Modified my ELF loader to load the
code from the section headers instead of program headers
Attempted to build newlib/libgloss separately (which failed)
Linked the libraries (libc, libnosys) through the ld script using GROUP, gcc and ld
I'm not quite sure what other information I should include with this, but I'd be happy to include what I can.
Edit: To verify, the page faults occurring are not at the addresses of the failing functions; they are elsewhere in the program. For example, when I call fopen(), located at 0x08048170, I will page fault at 0xA00A316C.
Edit 2:
Relevant code for loading ELF:
int krun(u8int *name) {
int fd = kopen(name);
Elf32_Ehdr *ehdr = kmalloc(sizeof(Elf32_Ehdr*));
read(fd, ehdr, sizeof(Elf32_Ehdr));
if (ehdr->e_ident[0] != 0x7F || ehdr->e_ident[1] != 'E' || ehdr->e_ident[2] != 'L' || ehdr->e_ident[3] != 'F') {
kfree(ehdr);
return -1;
}
int pheaders = ehdr->e_phnum;
int phoff = ehdr->e_phoff;
int phsize = ehdr->e_phentsize;
int sheaders = ehdr->e_shnum;
int shoff = ehdr->e_shoff;
int shsize = ehdr->e_shentsize;
for (int i = 0; i < pheaders; i++) {
lseek(fd, phoff + phsize * i, SEEK_SET);
Elf32_Phdr *phdr = kmalloc(sizeof(Elf32_Phdr*));
read(fd, phdr, sizeof(Elf32_Phdr));
u32int page = PMMAllocPage();
int flags = 0;
if (phdr->p_flags & PF_R) flags |= PAGE_PRESENT;
if (phdr->p_flags & PF_W) flags |= PAGE_WRITE;
int pages = (phdr->p_memsz / 0x1000) + 1;
while (pages >= 0) {
u32int mapaddr = (phdr->p_vaddr + (pages * 0x1000)) & 0xFFFFF000;
map(mapaddr, page, flags | PAGE_USER);
pages--;
}
lseek(fd, phdr->p_offset, SEEK_SET);
read(fd, (void *)phdr->p_vaddr, phdr->p_filesz);
kfree(phdr);
}
// Removed: code block that zeroes .bss: it's already zeroed whenever I check it anyways
// Removed: code block that creates thread and adds it to scheduler
kfree(ehdr);
return 0;
}
Edit 3: I've noticed that if I call a system call, such as write(), and then call printf() two or more times, I will get an unknown opcode interrupt. Odd.
Whoops! Figured it out: when I map the virtual address, I should allocate a new page each time, like so:
map(mapaddr, PMMAllocPage(), flags | PAGE_USER);
Now it works fine.
For those curious as to why it didn't work: when I wasn't including printf(), the size of the program was under 0x1000 bytes, so mapping with only one page was okay. When I include printf() or fopen(), the size of the program was much bigger so that's what caused the issue.
Is it possible to pass a block of code, for example:
int i = 0;
while (i < [array count]) {
//Code to pass in here
i++;
}
Reason being that i need to perform various actions on every item in an array at different times, it'd be nice to have 1 method and pass it a block of code to run.
Have you considered using blocks. It's just an idea and not working or compilable code
typedef int (^block_t)();
-(void) methodName:(block_t) code_block
{
int i = 0;
while (i < [array count]) {
code_block() //Code to pass in here
i++;
}
block_t youCode = ^{ NSLog("Just an example"); }
[self methodName:youCode];
You can definitely iterate an array and process a block of code on it. This feature has been a standard part of Objective C since 2.0, iOS since 4.0 and in addition was included in Snow Leopard. If you look up the NSArray class reference you will find the following functions:
enumerateObjectsAtIndexes:options:usingBlock:
Executes a given block using the
objects in the array at the specified
indexes.
enumerateObjectsUsingBlock: Executes a
given block using each object in the
array, starting with the first object
and continuing through the array to
the last object.
enumerateObjectsWithOptions:usingBlock:
Executes a given block using each
object in the array.
You can define the code block to be executed globally in your implementation file, or in place where its needed. You can find some good examples on block programming here: http://thirdcog.eu/pwcblocks/.
It sounds like you want "blocks", which are a feature of Objective-C similar to "lambdas", "anonymous functions" and "closures" in other languages.
See Apple's documentation: Blocks Programming Topics
You should put the code into a method and call the method like so:
-(void)foo{
int i = 0;
while (i < [array count]) {
[self myMethod];
i++;
}
}
-(void)myMethod{
//Code to pass in here
}
You could also store the method as a variable allowing you to change which method is called
SEL methodToCall = #selector(myMethod);
-(void)foo{
int i = 0;
while (i < [array count]){
[self performSelector:methodToCall];
i++;
}
}
-(void)myMethod{
//Code to pass in here
}
first of all you could give a more detailed example.
second you could take a look at Action or Func in case you need a return message (well something equivalent for obj-C if exists)
but again, not understanding what you need to do, it is hard to give you an answer
cause from you Q i could understand as #Trevor did that you need to run a method:
int i = 0;
while (i < [array count]) {
if (i % 2)
EvenMethod(array[i])
else
OddMethod(array[i])
i++;
}
If you can live with 4.0+ compatibility, I highly recommend the use of blocks.
- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
gives you all you need and you can define your block right where you need it. There are some other variants of this, too. Please refer to the 'NSArray' documentation.
Why not just define functions that do what you want, and call them at various times with the items in your array as arguments?
If your concern is that you don't want redundant code with multiple while loops you have here, you could write a function that takes an array and a function as an argument, then applies that function to every element in the array.
Adapted from here:
//------------------------------------------------------------------------------------
// 2.6 How to Pass a Function Pointer
// <pt2Func> is a pointer to a function which returns void and takes an NSObject*
void DoForAllItems( NSArray* array, void (*pt2Func)(NSObject*) )
{
int i = 0;
while (i < [array count]) {
(*pt2Func)([array objectAtIndex:i]);
i++;
}
}
// 'DoIt' takes an NSObject*
void DoIt (NSObject* object){ NSLog(#"DoIt"); }
// execute example code
void Pass_A_Function_Pointer()
{
NSArray* array= [NSArray arrayWithObjects:#"1", #"2", nil];
DoForAllItems(array, &DoIt);
}
http://thirdcog.eu/pwcblocks/#objcblocks
Blocks were added recently to Objective-C I hope they have found their way to the Iphone also.
and it was anwered here also before:
Using Objective-C Blocks
Regards
If you are using Objective C++, I would strongly recommend function objects (even over blocks). They have a nice syntax, are easy to use, and are supported everywhere on modern C++ compilers (MSVC++11, GNUC++11, and LLVMC++11):
void go( function<void (int arg)> func )
{
int i = 0;
while (i < [array count]) {
//Code to pass in here
func( i ) ; // runs func on i
i++;
}
}
calling it:
go( []( int arg ){ // the square brackets are the "capture"
printf( "arg was %d\n", arg ) ; // arg takes on whatever value was passed to it,
// just like a normal C function
} ) ;