Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repeated fields with primitive non Object types throw an exception when printing #26

Open
tedjt opened this issue Jun 6, 2012 · 2 comments

Comments

@tedjt
Copy link

tedjt commented Jun 6, 2012

I have a message that defines a repeated int64. In the generated MessagePb objective-C class,

the - (void) writeDescriptionTo:(NSMutableString_) output withIndent:(NSString_) indent

method fails since the auto-generated code attempts to do fast enumeration over the items like so

for (NSNumber* value in self.itemsArray) {
[output appendFormat:@"%@%@: %@\n", indent, @"items", value];
}

in this case 'value' is actually of type PBArrayValueTypeInt64, which causes the exception to be thrown in line 186 of PBArray.m

Suggestions on how to fix this to return a new array of NSNumbers around primitive types?

@emiliopavia
Copy link

I had the same issue. Just replace the following method in the PBArray.m file:

- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
{
    NSUInteger count = 0;
    // This is the initialization condition, so we'll do one-time setup here.
    // Ensure that you never set state->state back to 0, or use another method to detect initialization
    // (such as using one of the values of state->extra).
    if(state->state == 0) {
        // We are not tracking mutations, so we'll set state->mutationsPtr to point into one of our extra values,
        // since these values are not otherwise used by the protocol.
        // If your class was mutable, you may choose to use an internal variable that is updated when the class is mutated.
        // state->mutationsPtr MUST NOT be NULL.
        state->mutationsPtr = &state->extra[0];
    }
    // Now we provide items, which we track with state->state, and determine if we have finished iterating.
    if(state->state < _count) {
        // Set state->itemsPtr to the provided buffer.
        // Alternate implementations may set state->itemsPtr to an internal C array of objects.
        // state->itemsPtr MUST NOT be NULL.
        state->itemsPtr = stackbuf;
        // Fill in the stack array, either until we've provided all items from the list
        // or until we've provided as many items as the stack based buffer will hold.
        while((state->state < _count) && (count < len)) {
            switch (_valueType) {
                case PBArrayValueTypeObject:
                    stackbuf[count] = ((id *)_data)[state->state];
                    break;
                case PBArrayValueTypeBool:
                    stackbuf[count] = [NSNumber numberWithBool:((BOOL *)_data)[state->state]];
                    break;
                case PBArrayValueTypeInt32:
                    stackbuf[count] = [NSNumber numberWithInt:((int32_t *)_data)[state->state]];
                    break;
                case PBArrayValueTypeUInt32:
                    stackbuf[count] = [NSNumber numberWithUnsignedInt:((uint32_t *)_data)[state->state]];
                    break;
                case PBArrayValueTypeInt64:
                    stackbuf[count] = [NSNumber numberWithLongLong:((int64_t *)_data)[state->state]];
                    break;
                case PBArrayValueTypeUInt64:
                    stackbuf[count] = [NSNumber numberWithUnsignedLongLong:((uint64_t *)_data)[state->state]];
                    break;
                case PBArrayValueTypeFloat:
                    stackbuf[count] = [NSNumber numberWithFloat:((Float32 *)_data)[state->state]];
                    break;
                case PBArrayValueTypeDouble:
                    stackbuf[count] = [NSNumber numberWithDouble:((Float64 *)_data)[state->state]];
                    break;
                default:
                    break;
            }

            state->state++;
            count++;
        }
    }
    else {
        // We've already provided all our items, so we signal we are done by returning 0.
        count = 0;
    }
    return count;
}

This method is a little bit slower than the original one (that just returns the pointer to the _data array) but it works in all cases. If you want you can put a conditional and leave the default implementation if _valueType is equal to PBArrayValueTypeObject but in this way the code is more elegant.

@tedjt
Copy link
Author

tedjt commented Jun 25, 2012

Thanks! - this works great. I tried to do something similar but was missing the part to set state->itemsPtr to stackbuf.

Packetdancer pushed a commit to Packetdancer/protobuf-objc that referenced this issue Feb 4, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants