iOS NSArray objectAtIndex beyond bounds - ios

I have a UITableView that is populated from an array of data that is parsed from an XML feed. Im struggling to find the cause of this error and was wondering if anyone can help me. The error does not occur very often. It only occurs when the array count is large, for example 10-15 objects and then once refreshed, they array is then a lower number, like 3 - 4 objects. Normally the error is thrown on this line: FCCall *currentCall = [[dataController callsArray] objectAtIndex:((indexPath.row - 1 ) / 2)]; I added an exception breakpoint to break On Throw for All Exception and below is what it returned. I understand what the error is saying but cannot find the origin and it is very difficult to re-produce.
CoreFoundation`-[__NSArrayM objectAtIndex:]:
0x329cce54: push {r4, r5, r7, lr}
0x329cce56: add r7, sp, #8
0x329cce58: sub sp, #8
0x329cce5a: movw r1, #62216
0x329cce5e: mov r4, r2
0x329cce60: movt r1, #2113
0x329cce64: add r1, pc
0x329cce66: ldr r1, [r1]
0x329cce68: ldr r1, [r0, r1]
0x329cce6a: cmp r1, r4
0x329cce6c: bhi 0x329ccef8 ; -[__NSArrayM objectAtIndex:] + 164
0x329cce6e: movw r0, #49640
0x329cce72: cmp r1, #0
0x329cce74: movt r0, #2111
0x329cce78: add r0, pc
0x329cce7a: ldr r0, [r0]
0x329cce7c: ldr r0, [r0]
0x329cce7e: beq 0x329cce9c ; -[__NSArrayM objectAtIndex:] + 72
0x329cce80: movw r2, #17054
0x329cce84: subs r5, r1, #1
0x329cce86: movt r2, #2113
0x329cce8a: movw r3, #61062
0x329cce8e: movt r3, #16
0x329cce92: add r2, pc
0x329cce94: add r3, pc
0x329cce96: strd r4, r5, [sp]
0x329cce9a: b 0x329cceb2 ; -[__NSArrayM objectAtIndex:] + 94
0x329cce9c: movw r2, #17044
0x329ccea0: movt r2, #2113
0x329ccea4: movw r3, #61034
0x329ccea8: movt r3, #16
0x329cceac: add r2, pc
0x329cceae: str r4, [sp]
0x329cceb0: add r3, pc
0x329cceb2: movs r1, #0
0x329cceb4: bl 0x329dce60 ; CFStringCreateWithFormat
0x329cceb8: bl 0x329c897c ; CFMakeCollectable
0x329ccebc: mov r1, r0
0x329ccebe: movs r0, #0
0x329ccec0: bl 0x329ffa8c ; _CFAutoreleasePoolAddObject
0x329ccec4: movw r2, #50122
0x329ccec8: mov r3, r0
0x329cceca: movt r2, #2111
0x329ccece: movw r1, #25010
0x329cced2: add r2, pc
0x329cced4: movt r1, #2112
0x329cced8: movw r0, #26280
0x329ccedc: ldr r2, [r2]
0x329ccede: add r1, pc
0x329ccee0: movt r0, #2112
0x329ccee4: ldr r1, [r1]
0x329ccee6: movs r4, #0
0x329ccee8: add r0, pc
0x329cceea: str r4, [sp]
0x329cceec: ldr r0, [r0]
0x329cceee: ldr r2, [r2]
0x329ccef0: blx 0x32abfeec ; symbol stub for: -[NSMutableOrderedSet removeObjectsInRange:inOrderedSet:]
0x329ccef4: blx 0x32abfe8c ; symbol stub for: -[NSMutableOrderedSet removeObjectsAtIndexes:]
0x329ccef8: movw r1, #62064
0x329ccefc: movt r1, #2113
0x329ccf00: movw r3, #62048
0x329ccf04: add r1, pc
0x329ccf06: movt r3, #2113
0x329ccf0a: movw r2, #62048
0x329ccf0e: ldr r1, [r1]
0x329ccf10: add r3, pc
0x329ccf12: movt r2, #2113
0x329ccf16: ldr r3, [r3]
0x329ccf18: add r2, pc
0x329ccf1a: ldr r2, [r2]
0x329ccf1c: ldr r1, [r0, r1]
0x329ccf1e: ldr r3, [r0, r3]
0x329ccf20: ldr r0, [r0, r2]
0x329ccf22: add.w r2, r4, r1, lsr #2
0x329ccf26: sub.w r1, r2, r3, lsr #2
0x329ccf2a: lsrs r3, r3, #2
0x329ccf2c: cmp r3, r2
0x329ccf2e: it hi
0x329ccf30: movhi r1, r2
0x329ccf32: ldr.w r0, [r0, r1, lsl #2]
0x329ccf36: add sp, #8
0x329ccf38: pop {r4, r5, r7, pc}
0x329ccf3a: nop
0x329ccf3c: nop
0x329ccf3e: nop
Code:
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Returns the cell for the given indexPath
static NSString *cellidentifier1 = #"cell1";
static NSString *cellidentifier2 = #"cell2";
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"dark-background.jpg"]];
self.tableView.separatorColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"dark-background.jpg"]];
// Invisible Cell
if (indexPath.row % 2 == 0) {
UITableViewCell * cell2 = [theTableView dequeueReusableCellWithIdentifier:cellidentifier2];
if (cell2 == nil) {
cell2 = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellidentifier2];
[cell2.contentView setAlpha:0];
[cell2 setUserInteractionEnabled:NO];
[cell2 setBackgroundColor:[UIColor clearColor]];
}
return cell2;
}
// Standard Cell
SideSwipeTableViewCell *cell = (SideSwipeTableViewCell *)[theTableView dequeueReusableCellWithIdentifier:cellidentifier1];
if (cell == nil) {
cell = [[SideSwipeTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellidentifier1];
}
if ([dataController numberOfCalls] >= 1) {
FCCall *currentCall = [[dataController callsArray] objectAtIndex:((indexPath.row - 1 ) / 2)];
cell.callLabel.text = currentCall.call;
cell.locationLabel.text = currentCall.location;
cell.wcccaNumberLabel.text = currentCall.wcccaNumber;
cell.callNumberLabel.text = currentCall.callnumber;
// Remove leading white space from units string
NSString *units = [currentCall.units stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
cell.unitsLabel.text = units;
cell.stationLabel.text = currentCall.station;
}
return cell;
}
Method that refreshes the array:
- (void)refreshData:(id)object success:(void (^)(NSURLRequest *request, NSURL *url, NSArray *calls))success failure:(void (^)(NSURLRequest *request, NSURL *url, NSError *error))failure
{
NSLog(#"Refresh Started");
// Start the network activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
// Check to make sure we can even make an HTTP request
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.wccca.com/PITS"]];
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Reachable");
// Get the URL we are going to use to parse with
[FCDataController parserURL:[NSURL URLWithString:#"http://www.wccca.com/PITS"] completion:^(NSURL *url) {
NSURLRequest *parserRequest = [NSURLRequest requestWithURL:url];
AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:parserRequest success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
// Remove all data from our previous calls aray
[self performSelectorOnMainThread:#selector(removeCallsFromArray) withObject:nil waitUntilDone:YES];
// Set the delegate for the XMLParser and start the parse operation
XMLParser.delegate = self;
BOOL successful = [XMLParser parse];
// Determine if the parse operation was a success or not
if (!successful) {
// Return the failure block because the parser failed
failure(request, url, [FCErrors parserError]);
// Stop the network activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
else {
// Return the success block
success(request, url, calls);
// Stop the network activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
NSLog(#"Refresh Finished");
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser) {
NSLog(#"AFXMLOperation Error: %#", error.localizedDescription);
// Remove all data from our previous calls aray
[self performSelectorOnMainThread:#selector(removeCallsFromArray) withObject:nil waitUntilDone:YES];
failure(parserRequest, url, [FCErrors badURLError]);
// Stop the network activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"Refresh Finished");
}];
[operation start];
}];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Unreachable. AFHTTPRequestOperation Error: %#", error.localizedDescription);
// Remove all data from our previous calls aray
[self performSelectorOnMainThread:#selector(removeCallsFromArray) withObject:nil waitUntilDone:YES];
failure(request, nil, [FCErrors networkError]);
// Stop the network activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(#"Refresh Finished");
}];
[requestOperation start];
}

If your underlying data model has changed (such as refreshing your data that the table needs to display), you need to call reloadData on the tableView, otherwise it might request data for a row that no longer exists.

Related

Method swizzle not working on iOS 10.1

I want to swizzle the method #property string in UIPasteboard:
+ (void) load {
....
[UIPasteboard jr_swizzleMethod:#selector(string) withMethod:#selector(stringSwizzle) error:nil];
[UIPasteboard jr_swizzleMethod:#selector(setString:) withMethod:#selector(setStringSwizzle:) error:nil];
....
}
When I called [[UIPasteboard generalPasteboard] setString:#"test"]; it enter my swizzle method. It works on iOS 7, iOS 8, and iOS 9. However, it failed on iOS 10.
The assembly is differnt of a test method:
- (void) pasteboradTest {
[aUIPasteboard setString:#"test"];
}
on iOS 9:
0xced0a <+0>: push {r7, lr}
0xced0c <+2>: mov r7, sp
0xced0e <+4>: sub sp, #0x8
0xced10 <+6>: movw r2, #0xa51c
0xced14 <+10>: movt r2, #0x0
0xced18 <+14>: add r2, pc
0xced1a <+16>: movw r3, #0xa2e2
0xced1e <+20>: movt r3, #0x0
0xced22 <+24>: add r3, pc
0xced24 <+26>: ldr r3, [r3]
0xced26 <+28>: movw r9, #0xbc8e
0xced2a <+32>: movt r9, #0x0
0xced2e <+36>: add r9, pc
0xced30 <+38>: movw r12, #0xc298
0xced34 <+42>: movt r12, #0x0
0xced38 <+46>: add r12, pc
0xced3a <+48>: str r0, [sp, #0x4]
0xced3c <+50>: str r1, [sp]
0xced3e <+52>: ldr.w r0, [r12]
0xced42 <+56>: ldr.w r1, [r9]
0xced46 <+60>: blx r3
0xced48 <+62>: add sp, #0x8
0xced4a <+64>: pop {r7, pc}
on iOS 10:
0x10008f78c <+0>: stp x29, x30, [sp, #-16]!
0x10008f790 <+4>: mov x29, sp
0x10008f794 <+8>: sub sp, sp, #16 ; =16
0x10008f798 <+12>: adrp x8, 9
0x10008f79c <+16>: add x8, x8, #592 ; =592
0x10008f7a0 <+20>: adrp x9, 11
0x10008f7a4 <+24>: add x9, x9, #3480 ; =3480
0x10008f7a8 <+28>: adrp x10, 12
0x10008f7ac <+32>: add x10, x10, #1776 ; =1776
0x10008f7b0 <+36>: str x0, [sp, #8]
0x10008f7b4 <+40>: str x1, [sp]
0x10008f7b8 <+44>: ldr x10, [x10]
0x10008f7bc <+48>: ldr x1, [x9]
0x10008f7c0 <+52>: mov x0, x10
0x10008f7c4 <+56>: mov x2, x8
0x10008f7c8 <+60>: bl 0x100094cb8 ; symbol stub for: objc_msgSend
0x10008f7cc <+64>: mov sp, x29
0x10008f7d0 <+68>: ldp x29, x30, [sp], #16
0x10008f7d4 <+72>: ret
UIPasteboard become a class cluster in iOS 10. The easiest way to notice that is to stop on breakpoint in your app and perform following command in lldb:
(lldb) po [UIPasteboard generalPasteboard]
<_UIConcretePasteboard: 0x6000000087a0>
That's the reason why swizzling doesn't work - you change implementation in UIPasteboard class, but your application invokes implementation of _UIConcretePasteboard private subclass.
You may try to workaround this issue with following code:
+ (void) load {
// ....
[[[UIPasteboard generalPasteboard] class] jr_swizzleMethod:#selector(string) withMethod:#selector(stringSwizzle) error:nil];
[[[UIPasteboard generalPasteboard] class] jr_swizzleMethod:#selector(setString:) withMethod:#selector(setStringSwizzle:) error:nil];
// ....
}
Of course, it's not the safe way to implement swizzling for class cluster - there is no any guarantee that you will not encounter any other private UIPasteboard subclass in runtime.

Crash when calling dispatch_source_create() two times in a row

Consider the following code:
#interface ViewController ()
#property (nonatomic, strong) dispatch_source_t source;
#end
#implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_resume(self.source);
dispatch_source_set_timer(self.source, dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), 0.2 * NSEC_PER_SEC, 0.1 * NSEC_PER_SEC);
dispatch_source_set_event_handler(self.source, ^{
NSLog(#"%s",__func__);
});
}
#end
If I use dispatch_source_create to create the same DISPATCH_SOURCE_TYPE_TIMER twice, the app will crash. Why?
Is there any difference between creating a dispatch source once and twice like in above example?
libdispatch.dylib`_dispatch_xref_dispose:
0x10015e174 <+0>: ldr w8, [x0, #48]
0x10015e178 <+4>: cmp w8, #2 ; =2
0x10015e17c <+8>: b.hs 0x10015e184 ; <+16>
0x10015e180 <+12>: ret
0x10015e184 <+16>: stp x20, x21, [sp, #-16]!
0x10015e188 <+20>: adrp x20, 41
0x10015e18c <+24>: add x20, x20, #3849 ; =3849
0x10015e190 <+28>: adrp x21, 46
0x10015e194 <+32>: add x21, x21, #2440 ; =2440
0x10015e198 <+36>: str x20, [x21]
0x10015e19c <+40>: ldp x20, x21, [sp], #16
-> 0x10015e1a0 <+44>: brk #0x1
As they say, a picture is worth a thousand words:
Basically you're releasing a suspended dispatch object, which seems to be prohibited by CGD.
Resuming the first timer will make the crash go away:
self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_resume(self.source);
self.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_resume(self.source);

Facing Issue with Share Extension from Sqlite database

I have an iOS App which has a sqlite DB and I am trying to implement Share extension. Hence, I have this DB shared by the main App as well as the share extension.
Following is my implementation
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *AppGroupId = #"XXXX";
NSURL *groupContainerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:AppGroupId];
NSString *sharedDirectory = [groupContainerURL path];
sqliteDb = [sharedDirectory stringByAppendingPathComponent:#"MYDB.sqlite"];
success = [fileManager fileExistsAtPath:sqliteDb];
NSLog(#"path : %#", sqliteDb);
If I put my DB in NSDocument directory (without implementing share extension), everything works fine .
However, if I move it to shared directory and implement sharing extension, the app starts to crash when it goes in background.
Following are the logs and unfortunately I have not been able to debug why this is happening. Any help would be truly appreciated
The Crash log differ very time
like following
libsystem_kernel.dylib`mach_msg_trap:
0x31ae8504 <+0>: mov r12, sp
0x31ae8508 <+4>: push {r4, r5, r6, r8}
0x31ae850c <+8>: ldm r12, {r4, r5, r6}
0x31ae8510 <+12>: mvn r12, #30
0x31ae8514 <+16>: svc #0x80
-> 0x31ae8518 <+20>: pop {r4, r5, r6, r8}
0x31ae851c <+24>: bx lr
Foundation`-[NSConcreteMapTable dealloc]:
0x245b6f68 <+0>: push {r4, r5, r6, r7, lr}
0x245b6f6a <+2>: add r7, sp, #0xc
0x245b6f6c <+4>: push.w {r8, r10}
0x245b6f70 <+8>: sub sp, #0x8
0x245b6f72 <+10>: mov r4, r0
0x245b6f74 <+12>: movw r0, #0xa10
0x245b6f78 <+16>: movt r0, #0xd9f
0x245b6f7c <+20>: movw r1, #0xa0e
0x245b6f80 <+24>: add r0, pc
0x245b6f82 <+26>: movt r1, #0xd9f
0x245b6f86 <+30>: add r1, pc
0x245b6f88 <+32>: ldr.w r8, [r0]
0x245b6f8c <+36>: ldr r5, [r1]
0x245b6f8e <+38>: ldr.w r10, [r4, r8]
0x245b6f92 <+42>: adds r6, r4, r5
0x245b6f94 <+44>: mov r0, r6
0x245b6f96 <+46>: mov r1, r10
0x245b6f98 <+48>: bl 0x24644e10 ; empty
0x245b6f9c <+52>: ldr r0, [r4, r5]
0x245b6f9e <+54>: mov r1, r10
0x245b6fa0 <+56>: ldr r2, [r6, #0x30]
0x245b6fa2 <+58>: blx r2
0x245b6fa4 <+60>: movw r0, #0x9e4
0x245b6fa8 <+64>: mov.w r10, #0x0
0x245b6fac <+68>: movt r0, #0xd9f
0x245b6fb0 <+72>: str.w r10, [r4, r5]
0x245b6fb4 <+76>: add r0, pc
0x245b6fb6 <+78>: ldr.w r8, [r4, r8]
0x245b6fba <+82>: ldr r5, [r0]
0x245b6fbc <+84>: adds r6, r4, r5
0x245b6fbe <+86>: mov r1, r8
0x245b6fc0 <+88>: mov r0, r6
0x245b6fc2 <+90>: bl 0x24644e10 ; empty
-> 0x245b6fc6 <+94>: ldr r0, [r4, r5]
etc
NSString * const DataBaseName = #"MYDB.sqlite";
-(BOOL) createDataBase
{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:DataBaseName];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) return success;
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:DataBaseName];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error!!!" message:#"Failed to create writable database..." delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil];
[alert show];
}
return success;
}

UIImage setImage crash

I implemented a video player with ffmpeg. Each frame is decoded successfully and can be saved to a valid jpg file and can be show in UIImageView when running in emulator. However, the memory is unbounded growing when I run my app in emulator. Moreover, the app will crash after excuting p_diaplayNextFrame 2 times when running on device. If I comment self.imageView.image = frame;, memory is not leaked and app is not crashed in emulator or on device.
-(void)p_displayNextFrame
{
ZCVFrameSec *frameSec = [video getNextVideoFrameSec];
UIImage *frame = [frameSec toUIImage];
static int fi = 0;
NSAssert( [NSThread isMainThread], #"Fatal error: must be main thread" );
NSString *fileName = [Utilities documentsPath:[NSString stringWithFormat:#"image%06d.jpg",fi++]];
NSLog(#"p_displayNextFrame write image file: %#",fileName);
// frame is saved successfully as jpg, I can view it
[UIImageJPEGRepresentation(frame, 0.7) writeToFile:fileName atomically:YES];
// leak(but not crash) in emulator, crash on device
self.imageView.image = frame;
double delayInSeconds = 0.05;//1/30.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self p_displayNextFrame];
});
}
ZCVFrameSec's toUIImage
- (UIImage*) toUIImage
{
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, [self.data bytes], self.width * self.height * 3,kCFAllocatorNull);
NSAssert( [self.data length] == self.width * self.height * 3,
#"Fatal error: data length:%d, width:%d, height:%d, mul3=%d",
[self.data length],
self.width, self.height, self.width * self.height * 3 );
CGDataProviderRef provider = CGDataProviderCreateWithCFData(data);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGImageRef cgImage = CGImageCreate(self.width,
self.height,
8,
24,
3 * self.width,
colorSpace,
bitmapInfo,
provider,
NULL,
NO,
kCGRenderingIntentDefault);
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
CGColorSpaceRelease(colorSpace);
CGDataProviderRelease(provider);
CFRelease(data);
return image;
}
crash info:
vImage`__vConvert_RGB888toBGRA8888_block_invoke98:
0x2d72aeb0: push {r4, r5, r6, r7, lr}
0x2d72aeb2: add r7, sp, #0xc
0x2d72aeb4: push.w {r8, r10}
0x2d72aeb8: ldr r2, [r0, #0x14]
0x2d72aeba: ldr r2, [r2, #0x4]
0x2d72aebc: ldr r2, [r2, #0x10]
0x2d72aebe: cmp r2, #0x0
0x2d72aec0: beq.w 0x2d72b076 ; __vConvert_RGB888toBGRA8888_block_invoke98 + 454
0x2d72aec4: vldr d16, [pc, #440]
0x2d72aec8: vmov.i32 q10, #0xff000000
0x2d72aecc: lsl.w r9, r1, #0x3
0x2d72aed0: vldr d18, [pc, #436]
0x2d72aed4: mov.w r12, #0x0
0x2d72aed8: ldr.w r8, [r0, #24]
0x2d72aedc: add.w r5, r0, #0x1c
0x2d72aee0: add.w r6, r12, r9
0x2d72aee4: ldm r5, {r2, r4, r5}
0x2d72aee6: ldr r3, [r0, #0x28]
0x2d72aee8: ldr r1, [r0, #0x2c]
0x2d72aeea: mla r2, r2, r6, r8
0x2d72aeee: mla lr, r5, r6, r4
0x2d72aef2: mla r3, r1, r6, r3
0x2d72aef6: tst.w r3, #0xf
0x2d72aefa: bne 0x2d72af44 ; __vConvert_RGB888toBGRA8888_block_invoke98 + 148
0x2d72aefc: tst.w r2, #0xf
0x2d72af00: bne 0x2d72af80 ; __vConvert_RGB888toBGRA8888_block_invoke98 + 208
0x2d72af02: ldr r4, [r0, #0x30]
0x2d72af04: movs r1, #0x0
0x2d72af06: tst.w lr, #0xf
0x2d72af0a: bne 0x2d72afbc ; __vConvert_RGB888toBGRA8888_block_invoke98 + 268
0x2d72af0c: cmp r4, #0x10
0x2d72af0e: blo 0x2d72aff2 ; __vConvert_RGB888toBGRA8888_block_invoke98 + 322
0x2d72af10: ldr r4, [r0, #0x34]
0x2d72af12: vld3.8 {d0, d2, d4}, [r2]!
Thread 1: EXC_BAD_ACCESS (code=1,address=0x7403000)
Any hint is appreciated!!!
I think the problem was because ZCVFrameSec *frameSec got deallocate after it got out of scope of -(void)p_displayNextFrame method.
If you used CFDataCreateWithBytesNoCopy on the bytes array in frameSec, then the byte array might vanish with frameSec before you finished using it in your cgImage, or you could say, in your UIImage *frame. This caused a EXC_BAD_ACCESS exception.
That why changing to CFDataCreate instead of CFDataCreateWithBytesNoCopy worked.
To answer your next question, how you can avoid copying a frame, I think there are a lot of ways to do that. You may hold your frameSec all the time until you change imageView to the next frame then you can release it.
To do that you can only declare a property to hold the current frame. Like this :
-(void)p_displayNextFrame
{
ZCVFrameSec *frameSec = [video getNextVideoFrameSec];
UIImage *frame = [frameSec toUIImage];
static int fi = 0;
NSAssert( [NSThread isMainThread], #"Fatal error: must be main thread" );
NSString *fileName = [Utilities documentsPath:[NSString stringWithFormat:#"image%06d.jpg",fi++]];
NSLog(#"p_displayNextFrame write image file: %#",fileName);
// frame is saved successfully as jpg, I can view it
[UIImageJPEGRepresentation(frame, 0.7) writeToFile:fileName atomically:YES];
// leak(but not crash) in emulator, crash on device
self.imageView.image = frame;
// At your header you should declare : #property ZCVFrameSec *currentFrameSec;
self.currentFrameSec = frameSec;
double delayInSeconds = 0.05;//1/30.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self p_displayNextFrame];
});
}

iOS UIWebview crash if copy text from the displayed pdf

i've tried to search a lot inside stackoverflow and in google before ask my question.
Seems to be similar questions but for me without answer.
So i'm trying to ask!!
i've a view controller presented as presentModalViewController with inside a uitoolbar and a uiwebview.
In the web view is displayed a pdf file. The web view as default allow me to select a text and show to me the copy function of the standard UIMenuController.
At this point if i dismiss the view controller the app crash with this logged error showed in the console:
libobjc.A.dylib`objc_msgSend:
0x372daf68: teq.w r0, #0
0x372daf6c: beq 0x372dafaa ; objc_msgSend + 66
0x372daf6e: push.w {r3, r4}
0x372daf72: ldr r4, [r0]
0x372daf74: lsr.w r9, r1, #2
0x372daf78: ldr r3, [r4, #8]
0x372daf7a: add.w r3, r3, #8
0x372daf7e: ldr r12, [r3, #-8]
0x372daf82: and.w r9, r9, r12
0x372daf86: ldr.w r4, [r3, r9, lsl #2]
0x372daf8a: teq.w r4, #0
0x372daf8e: add.w r9, r9, #1
0x372daf92: beq 0x372dafa6 ; objc_msgSend + 62
0x372daf94: ldr.w r12, [r4]
0x372daf98: teq.w r1, r12
0x372daf9c: bne 0x372db17e ; objc_msgSendSuper_stret + 34
0x372daf9e: ldr.w r12, [r4, #8]
0x372dafa2: pop {r3, r4}
0x372dafa4: bx r12
0x372dafa6: pop {r3, r4}
0x372dafa8: b 0x372dafb0 ; objc_msgSend_uncached
0x372dafaa: mov.w r1, #0
0x372dafae: bx lr
I don't understand if this is a my error o a bug of the uiwebview
I've also tried to use CGPDFDocument for render a pdf page but i'm not able to show the UIMenuController and select the text and perform the standard copy action inside the document.
I've also tried to start with this excellent project but also in this i can not perform copy action - https://github.com/vfr/Reader
Basically these are the used code.
I'm working with iOS 5 with ARC
- (void)viewDidLoad
{
[super viewDidLoad];
if (![urlPdfFile hasPrefix:#"http"]) {
NSString *ofType = [urlPdfFile pathExtension];
NSString *pathForResource = [[[urlPdfFile lastPathComponent] componentsSeparatedByString:#"."] objectAtIndex:0];
NSString *inDirectory = [urlPdfFile stringByDeletingLastPathComponent];
NSString *url = [[NSBundle mainBundle] pathForResource:pathForResource
ofType:ofType
inDirectory:inDirectory];
[self loadCatalogueFile:url];
} else {
[self loadFile:urlPdfFile];
}
}
- (void)viewDidUnload
{
[self setMyWebView:nil];
[super viewDidUnload];
}
-(void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.view removeFromSuperview];
self.view=nil;
[self viewDidUnload];
}
-(void)loadCatalogueFile:(NSString*)url {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:url]];
[myWebView loadRequest:request];
}
-(void)loadFile:(NSString*)url
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[myWebView loadRequest:request];
}
-(void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
//
}
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
//
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
//
}
Thank you very much for your help!!!
Had the same problem.
Mine was caused because I retained the view controller which holds the UIWebView, and re-used it.
To fix it just create the view controller each time from scratch.

Resources