我正在使用https://github.com/IngmarStein/SignatureDemo中的来源向用户提供可以签名的视图。然后我将签名的图像发送到Heroku上运行的服务器。这在模拟器中运行良好。当我在实际设备(iPad)上测试时,该应用程序在此行崩溃:UIImagePNGRepresentation(signature)
。
处理签名提交的控制器方法: (signatureView是从前面提到的github repo下载的NISignatureView的一个实例)
- (IBAction)submit:(UIButton *)sender {
@try {
UIImage *signatureImage = [self.signatureView getSignatureImage];
if (signatureImage) {
void (^successBlock)(NSURLRequest *, NSHTTPURLResponse *, id) = ^(NSURLRequest *req, NSHTTPURLResponse *response, id JSON) {
[self signatureCaptured];
};
[self.helper sendSignature:signatureImage total:self.total orderId:self.orderId authToken:self.authToken successBlock:successBlock failureBlock:nil view:self.view];
} else {
[self signatureCaptured];
}
}
@catch (NSException *exception) {
NSLog(@"Exception occurred: %@, %@", exception, [exception userInfo]);
NSString *msg = [NSString stringWithFormat:@"There was an error capturing the signature. Please try again. \nError: %@", [exception name]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:msg delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
[alert show];
}
}
NISignatureView的getSignatureImage方法:
- (UIImage *)getSignatureImage {
if (!self.drawnSignature)
return nil;
CGFloat width = self.frame.size.width;
CGFloat height = self.frame.size.height;
NSInteger myDataLength = width * height * 4;
// allocate array and read pixels into it.
GLubyte *buffer = (GLubyte *) malloc(myDataLength);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
// gl renders "upside down" so swap top to bottom into new array.
// there's gotta be a better way, but this works.
GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width * 4; x++) {
buffer2[(((int) height - 1) - y) * (int) width * 4 + x] = buffer[y * 4 * (int) width + x];
}
}
// make data provider with data.
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);
// prep the ingredients
int bitsPerComponent = 8;
int bitsPerPixel = 32;
int bytesPerRow = 4 * width;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
// make the cgimage
CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
// then make the uiimage from that
UIImage *myImage = [[UIImage alloc] initWithCGImage:imageRef];
// release memory
CGImageRelease(imageRef);
CGColorSpaceRelease(colorSpaceRef);
CGDataProviderRelease(provider);
free(buffer);
free(buffer2);
return myImage;
}
从控制器调用的助手:
- (void)sendSignature:(UIImage *)signature total:(NSNumber *)total orderId:(NSNumber *)orderId authToken:(NSString *)authToken successBlock:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))successBlock failureBlock:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failureBlock view:(UIView *)view {
NSData *imageData = UIImagePNGRepresentation(signature);
MBProgressHUD *submit = [MBProgressHUD showHUDAddedTo:view animated:YES];
submit.labelText = @"Saving";
[submit show:NO];
NSString *url = [NSString stringWithFormat:@"%@?%@=%@", [NSString stringWithFormat:kDBCAPTURESIG([orderId intValue])], kAuthToken, authToken];
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:url]];
[client setParameterEncoding:AFJSONParameterEncoding];
NSDictionary *parameters = @{@"total" : total};
NSMutableURLRequest *request = [client multipartFormRequestWithMethod:@"POST" path:@"" parameters:parameters constructingBodyWithBlock:^(id <AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData name:@"signature" fileName:@"signature" mimeType:@"image/png"];
}];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *req, NSHTTPURLResponse *response, id json) {
[submit hide:NO];
if (successBlock) successBlock(req, response, json);
} failure:^(NSURLRequest *req, NSHTTPURLResponse *response, NSError *error, id json) {
[submit hide:NO];
if (failureBlock) failureBlock(req, response, error, json);
NSInteger statusCode = [[[error userInfo] objectForKey:AFNetworkingOperationFailingURLResponseErrorKey] statusCode];
NSString *alertMessage = [NSString stringWithFormat:@"There was an error processing this request. Status Code: %d", statusCode];
[[[UIAlertView alloc] initWithTitle:@"Error!" message:alertMessage delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
}];
[operation start];
}
应用程序在上面帮助程序的NSData *imageData = UIImagePNGRepresentation(signature);
处崩溃。来自调试器的快照:
更新
该应用程序不会每次都崩溃。崩溃发生在同一条线上,但有时只发生。我已经更新了描述以包含NISignatureView的getSignatureImage方法。某些对象在此方法结束时被释放。我想知道这是否与糟糕的访问错误有关。我很惭愧地说我还不了解释放和保留。
更新2
我在NISignatureView的NISignatureView属性的getSignatureImage
中释放或释放了对象。将释放/自由逻辑移动到单独的方法。在我将图像发送到服务器之后调用此方法。这似乎有效。没有遇到过崩溃。但我不知道我在做什么是解决这个问题的正确方法。签名视图是否需要释放这些对象?卸载视图时它们不会自动释放吗?