Andy Waite
Andy Waite

Reputation: 11076

Pointer handling with RubyMotion

I'm trying to port the following method to RubyMotion

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSInteger       dataLength = [data length];
    const uint8_t * dataBytes  = [data bytes];
    NSInteger       bytesWritten;
    NSInteger       bytesWrittenSoFar;

    bytesWrittenSoFar = 0;
    do {
        bytesWritten = [self.downloadStream write:&dataBytes[bytesWrittenSoFar] maxLength:dataLength - bytesWrittenSoFar];
        assert(bytesWritten != 0);
        if (bytesWritten == -1) {
            [self cleanupConnectionSuccessful:NO];
            break;
        } else {
            bytesWrittenSoFar += bytesWritten;
        }
    } while (bytesWrittenSoFar != dataLength);

    self.progressContentLength += dataLength;
}

(it's from robertmryan/download-manager)

This is what I have currently, which crashes on the call to downloadStream with connection:didReceiveData:': can't convert Fixnum into String (TypeError)

def connection(connection, didReceiveData:data)
  dataLength = data.length
  dataBytes = data.bytes
  bytesWritten = 0
  bytesWrittenSoFar = 0

  begin
    maxLength = dataLength - bytesWrittenSoFar
    buffer = dataBytes[bytesWrittenSoFar]
    bytesWritten = self.downloadStream.write buffer, maxLength: maxLength # CRASH
    if bytesWritten == -1
      self.cleanupConnectionSuccessful false
      break
    else
      bytesWrittenSoFar += bytesWritten
    end
  end while bytesWrittenSoFar != dataLength

  self.progressContentLength += dataLength

  if self.delegate.respondsToSelector('downloadDidReceiveData:')
    self.delegate.downloadDidReceiveData(self)
  end
end

I realise that my conversion ignores the pointers is likely naive and wrong. I've checked the RubyMotion docs, but they are a bit sparse, and my understanding of C isn't strong enough to know how to apply it here. Some advice would be much appreciated.

Upvotes: 4

Views: 528

Answers (1)

yonosoytu
yonosoytu

Reputation: 3319

The bytes method of NSData returns a Pointer type (http://www.rubymotion.com/developer-center/api/Pointer.html).

The [] method in the Pointer type gives you access to element at that position from the start of the pointer. It seems to me that bytes returns a Pointer of type “C” (unsigned char), so when you try to access the Pointer like dataBytes[bytesWrittenSoFar] you where only obtaining a Fixnum which was the value of that byte from the start of the pointer.

To do what you want to do you will need something like the following:

bytesWrittenSoFar = 0

begin
  maxLength = dataLength - bytesWrittenSoFar
  buffer = dataBytes + bytesWrittenSoFar
  bytesWritten = self.downloadStream.write buffer, maxLength: maxLength
  if bytesWritten == -1
    self.cleanupConnectionSuccessful false
    break
  else
    bytesWrittenSoFar += bytesWritten
  end
end while bytesWrittenSoFar != dataLength

I haven’t run it, but I hope it works.

Upvotes: 4

Related Questions