Using any UIStringDrawing methods on two threads simultaneously causes a crash. My understanding was that all UIStringDrawing methods were thread safe from iOS 4.0.
This code (that does nothing of any use) demonstrates the problem:
dispatch_queue_t queue = dispatch_queue_create("com.queue", NULL);
for (int i = 0; i < 10000; i++) {
dispatch_async(queue, ^{
NSString *string = #"My string";
CGSize size = [string sizeWithFont:[UIFont boldSystemFontOfSize:13]];
});
}
for (int i = 0; i < 10000; i++) {
NSString *string = #"My string";
CGSize size = [string sizeWithFont:[UIFont boldSystemFontOfSize:13]];
}
dispatch_release(queue);
The app crashes after a few iterations of the loops with the following backtrace:
* thread #1: tid = 0x2403, 0x00ad40c8, stop reason = EXC_BAD_ACCESS (code=2, address=0xad40c8)
frame #0: 0x00ad40c8
frame #1: 0x36bc4252 WebCore`WebCore::Font::Font(WebCore::FontPlatformData const&, WTF::PassRefPtr<WebCore::FontSelector>) + 90
frame #2: 0x36bc41f2 WebCore`WebCore::Font::Font(WebCore::FontPlatformData const&, WTF::PassRefPtr<WebCore::FontSelector>) + 10
frame #3: 0x38f0368e WebKit`rendererForFont(__GSFont*) + 246
frame #4: 0x38f03230 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:forWidth:ellipsis:letterSpacing:resultRange:] + 200
frame #5: 0x38f03162 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:forWidth:ellipsis:letterSpacing:] + 66
frame #6: 0x38f04532 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:] + 58
frame #7: 0x361dc5d2 UIKit`-[NSString(UIStringDrawing) sizeWithFont:] + 46
frame #8: 0x00060ca8 myApp`-[TAViewController drawingTest] + 216 at TAViewController.m:157
frame #9: 0x38da1e66 Foundation`__NSFireDelayedPerform + 450
frame #10: 0x3aa47856 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14
frame #11: 0x3aa47502 CoreFoundation`__CFRunLoopDoTimer + 274
frame #12: 0x3aa46176 CoreFoundation`__CFRunLoopRun + 1230
frame #13: 0x3a9b923c CoreFoundation`CFRunLoopRunSpecific + 356
frame #14: 0x3a9b90c8 CoreFoundation`CFRunLoopRunInMode + 104
frame #15: 0x3a8a433a GraphicsServices`GSEventRunModal + 74
frame #16: 0x3622c288 UIKit`UIApplicationMain + 1120
frame #17: 0x0005f08c myApp`main + 96 at main.m:16
thread #5: tid = 0x2a03, 0x00ad40c8, stop reason = EXC_BAD_ACCESS (code=2, address=0xad40c8)
frame #0: 0x00ad40c8
frame #1: 0x36bc4252 WebCore`WebCore::Font::Font(WebCore::FontPlatformData const&, WTF::PassRefPtr<WebCore::FontSelector>) + 90
frame #2: 0x36bc41f2 WebCore`WebCore::Font::Font(WebCore::FontPlatformData const&, WTF::PassRefPtr<WebCore::FontSelector>) + 10
frame #3: 0x38f0368e WebKit`rendererForFont(__GSFont*) + 246
frame #4: 0x38f03230 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:forWidth:ellipsis:letterSpacing:resultRange:] + 200
frame #5: 0x38f03162 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:forWidth:ellipsis:letterSpacing:] + 66
frame #6: 0x38f04532 WebKit`-[NSString(WebStringDrawing) _web_sizeWithFont:] + 58
frame #7: 0x361dc5d2 UIKit`-[NSString(UIStringDrawing) sizeWithFont:] + 46
frame #8: 0x00060d5c myApp`__31-[TAViewController drawingTest]_block_invoke_0 + 116 at TAViewController.m:150
frame #9: 0x339f0792 libdispatch.dylib`_dispatch_call_block_and_release + 10
frame #10: 0x339f3b3a libdispatch.dylib`_dispatch_queue_drain + 142
frame #11: 0x339f167c libdispatch.dylib`_dispatch_queue_invoke + 44
frame #12: 0x339f4612 libdispatch.dylib`_dispatch_root_queue_drain + 210
frame #13: 0x339f47d8 libdispatch.dylib`_dispatch_worker_thread2 + 92
frame #14: 0x37f957f0 libsystem_c.dylib`_pthread_wqthread + 360
frame #15: 0x37f95684 libsystem_c.dylib`start_wqthread + 8
My understanding was that UIStringDrawing methods were thread safe from iOS 4. I expect that these loops should complete with no errors.
The crash occurs when running on an iPhone running iOS 6 (tested on iPhone 5) but does NOT occur when running on an iPhone running iOS 5 (tested on iPhone 4) or the simulator (tested with iOS 6).
I have implemented what I thought was a fix by serialising any draw calls using CGD:
- (void)serialiseDrawing:(void (^)())block {
dispatch_sync(self.serialDrawingQueue, block);
}
- (dispatch_queue_t)serialDrawingQueue {
if (_serialDrawingQueue == NULL) _serialDrawingQueue = dispatch_queue_create("com.myApp.SerialDrawQueue", NULL);
return _serialDrawingQueue;
}
...and wrapping every draw call like this:
__block CGSize labelSize = CGSizeZero;
[[TAUtils sharedUtils] serialiseDrawing:^{
labelSize = [label.text sizeWithFont:label.font];
}];
This seems to have improved things a bit (all my UIStringDrawing calls happen on one thread). But it will still crash at times with a backtrace like this:
Exception Type: EXC_CRASH (SIGSEGV)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x3a28ee80 semaphore_wait_trap + 8
1 libdispatch.dylib 0x32851e90 _dispatch_thread_semaphore_wait + 8
2 libdispatch.dylib 0x32850680 _dispatch_barrier_sync_f_slow + 100
3 myApp 0x000c4330 -[TAUtils serialiseDrawing:] (TAUtils.m:305)
4 myApp 0x000edfd4 -[TAOmniBar updateLabel] (TAOmniBar.m:394)
5 myApp 0x000ee8d6 -[TAOmniBar handleNotification:] (TAOmniBar.m:461)
6 CoreFoundation 0x39820346 _CFXNotificationPost + 1418
7 Foundation 0x37b5838a -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
8 Foundation 0x37b5be9a -[NSNotificationCenter postNotificationName:object:] + 26
9 myApp 0x000f369a -[TAMyViewController update] (TAMyViewController.m:1308)
10 GLKit 0x328383ce -[GLKViewController _updateAndDraw] + 270
11 QuartzCore 0x39ffd77c CA::Display::DisplayLink::dispatch(unsigned long long, unsigned long long) + 156
12 QuartzCore 0x39ffd6d4 CA::Display::IOMFBDisplayLink::callback(__IOMobileFramebuffer*, unsigned long long, unsigned long long, unsigned long long, void*) + 60
13 IOMobileFramebuffer 0x31221fd4 IOMobileFramebufferVsyncNotifyFunc + 152
14 IOKit 0x39f7c5aa IODispatchCalloutFromCFMessage + 190
15 CoreFoundation 0x39899888 __CFMachPortPerform + 116
16 CoreFoundation 0x398a43e4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 32
17 CoreFoundation 0x398a4386 __CFRunLoopDoSource1 + 134
18 CoreFoundation 0x398a320a __CFRunLoopRun + 1378
19 CoreFoundation 0x39816238 CFRunLoopRunSpecific + 352
20 CoreFoundation 0x398160c4 CFRunLoopRunInMode + 100
21 GraphicsServices 0x39701336 GSEventRunModal + 70
22 UIKit 0x35089284 UIApplicationMain + 1116
23 myApp 0x000b806e main (main.m:16)
24 myApp 0x000b8024 start + 36
Thread 7 name: Dispatch queue: com.myApp.SerialDrawQueue
Thread 7:
0 WebCore 0x35a21410 WebCore::FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector>) + 156
1 WebCore 0x35a2124e WebCore::Font::Font(WebCore::FontPlatformData const&, WTF::PassRefPtr<WebCore::FontSelector>) + 86
2 WebCore 0x35a211ee WebCore::Font::Font(WebCore::FontPlatformData const&, WTF::PassRefPtr<WebCore::FontSelector>) + 6
3 WebKit 0x37d6068a rendererForFont(__GSFont*) + 242
4 WebKit 0x37d61796 -[NSString(WebStringDrawing) __web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:measureOnly:renderedStringOut:drawUnderline:] + 198
5 WebKit 0x37d616bc -[NSString(WebStringDrawing) __web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:measureOnly:renderedStringOut:] + 84
6 WebKit 0x37d6165e -[NSString(WebStringDrawing) __web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:measureOnly:] + 82
7 WebKit 0x37d61602 -[NSString(WebStringDrawing) _web_drawAtPoint:forWidth:withFont:ellipsis:letterSpacing:includeEmoji:] + 78
8 UIKit 0x35041960 -[NSString(UIStringDrawing) drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:] + 172
9 UIKit 0x3507de1e -[NSString(UIStringDrawing) drawAtPoint:forWidth:withFont:fontSize:lineBreakMode:baselineAdjustment:includeEmoji:] + 358
10 UIKit 0x3507dca4 -[NSString(UIStringDrawing) drawAtPoint:forWidth:withFont:fontSize:lineBreakMode:baselineAdjustment:] + 68
11 myApp 0x000d3300 -[TALabelManager textureCGImageForString:] (TALabelManager.m:859)
12 myApp 0x000d350a __39-[TALabelManager textureDataForString:]_block_invoke_0 (TALabelManager.m:875)
13 libdispatch.dylib 0x3284d5d8 _dispatch_client_callout + 20
14 libdispatch.dylib 0x3285080a _dispatch_barrier_sync_f_invoke + 22
15 myApp 0x000c4330 -[TAUtils serialiseDrawing:] (TAUtils.m:305)
16 myApp 0x000d3420 -[TALabelManager textureDataForString:] (TALabelManager.m:873)
17 myApp 0x000d0dde __block_global_0 (TALabelManager.m:516)
18 libdispatch.dylib 0x3284d790 _dispatch_call_block_and_release + 8
19 libdispatch.dylib 0x32850b36 _dispatch_queue_drain + 138
20 libdispatch.dylib 0x3284e678 _dispatch_queue_invoke + 40
21 libdispatch.dylib 0x32851610 _dispatch_root_queue_drain + 208
22 libdispatch.dylib 0x328517d4 _dispatch_worker_thread2 + 88
23 libsystem_c.dylib 0x36df27ee _pthread_wqthread + 358
24 libsystem_c.dylib 0x36df2680 start_wqthread + 4
I apologise for the long question but this is a serious problem for me and would really appreciate any help.
While trying to find a work around I noticed that iOS 6 introduces much more widespread integration of NSAttributedString and Core Text so I tried swapping all UIStringDrawing methods with the equivalent NSStringDrawing methods using NSAttributedString in place of NSString and it seems the crashes have stopped.
For example, I'm now using:
NSAttributedString *attribStr = [[NSAttributedString alloc] initWithString:#"My String"];
CGSize size = [attribStr size];
instead of:
NSString *str = #"My String";
CGSize size = [str sizeWithFont:font];
Adam is correct. UIStringDrawing methods are only safe to use from the main queue on iOS 6. You can either use NSStringDrawing methods or CoreText directly to perform rendering from background queues. This is a known issue, but feel free to file more bugs.
Adam Swinden's solution worked for me. Here's how I converted NSString's sizeWithFont:constrainedToSize::
What used to be:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font
constrainedToSize:(CGSize){width, CGFLOAT_MAX}];
Can be replaced with:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
NSAttributedString *attributedText =
[[NSAttributedString alloc]
initWithString:text
attributes:#
{
NSFontAttributeName: font
}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){width, CGFLOAT_MAX}
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
CGSize size = rect.size;
Please note the documentation mentions:
In iOS 7 and later, this method returns fractional sizes (in the size
component of the returned CGRect); to use a returned size to size
views, you must use raise its value to the nearest higher integer
using the ceil function.
So to pull out the calculated height or width to be used for sizing views, I would use:
CGFloat height = ceilf(size.height);
CGFloat width = ceilf(size.width);
Based on the Adam Swinden's and Mr T's answers I wrote 2 drop-in methods:
#implementation NSString (Extensions)
- (CGSize)threadSafeSizeWithFont:(UIFont *)font {
return [self threadSafeSizeWithFont:font constrainedToSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
}
- (CGSize)threadSafeSizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size {
// http://stackoverflow.com/questions/12744558/uistringdrawing-methods-dont-seem-to-be-thread-safe-in-ios-6
NSAttributedString *attributedText =
[[NSAttributedString alloc]
initWithString:self
attributes:#
{
NSFontAttributeName: font
}];
CGRect rect = [attributedText boundingRectWithSize:size
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
return rect.size;
}
#end
Related
I have been using this function to generate a time stamp. I found it somewhere here on Stack Overflow.
#objc public class var timestamp: String {
return "\(Int(NSDate().timeIntervalSince1970 * 1000))"
}
It has been working without issue, but I just got a EXC_BAD_INSTRUCTION:
fatal error: floating point value cannot be converted to Int because it is greater than Int.max
As the development of this app is nearing completion it makes me nervous to all of the sudden see it cause a EXC_BAD_INSTRUCTION. This is running in the Simulator, but I have a valid date and time set.
Any ideas or suggestions or are greatly appreciated. Below is the backtrace.
(lldb) bt
* thread #1: tid = 0x15c4d, 0x04a30393 libswiftCore.dylib`function signature specialization <Arg[0] = Exploded, Arg[1] = Exploded, Arg[2] = Dead, Arg[3] = Dead> of Swift._fatalErrorMessage (Swift.StaticString, Swift.StaticString, Swift.StaticString, Swift.UInt) -> () + 67, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
frame #0: 0x04a30393 libswiftCore.dylib function signature specialization <Arg[0] = Exploded, Arg[1] = Exploded, Arg[2] = Dead, Arg[3] = Dead> of Swift._fatalErrorMessage (Swift.StaticString, Swift.StaticString, Swift.StaticString, Swift.UInt) -> () + 67
* frame #1: 0x00afe0c9 TDTPhotoLib static
TDTDeviceUtilites.timestamp.getter(self=TDTPhotoLib.TDTDeviceUtilites) + 409 at TDTDeviceUtilites.swift:127
frame #2: 0x00166979 Oilist TDTPaintingViewController.finshedSession(sender=0x7aee0fb0, self=0x7e9d3800) -> () + 169 at TDTPaintingViewController.swift:1370
frame #3: 0x00102896 Oilist TDTOilistMenuPainting.goForward(sender=0x7aee0fb0, self=0x7c218770) -> () + 374 at TDTOilistMenuPainting.swift:149
frame #4: 0x0010290d Oilist #objc TDTOilistMenuPainting.goForward(UIButton!) -> () + 61 at TDTOilistMenuPainting.swift:0
frame #5: 0x018a80b5 libobjc.A.dylib -[NSObject performSelector:withObject:withObject:] + 84
frame #6: 0x0336ee38 UIKit -[UIApplication sendAction:to:from:forEvent:] + 118
frame #7: 0x0336edb7 UIKit -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 64
frame #8: 0x03512f3b UIKit -[UIControl sendAction:to:forEvent:] + 79
frame #9: 0x035132d4 UIKit -[UIControl _sendActionsForEvents:withEvent:] + 433
frame #10: 0x035122c1 UIKit -[UIControl touchesEnded:withEvent:] + 714
frame #11: 0x033ef52e UIKit -[UIWindow _sendTouchesForEvent:] + 1095
frame #12: 0x033f05cc UIKit -[UIWindow sendEvent:] + 1159
frame #13: 0x03391be8 UIKit -[UIApplication sendEvent:] + 266
frame #14: 0x03366769 UIKit _UIApplicationHandleEventQueue + 7795
frame #15: 0x02423e5f CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
frame #16: 0x02419aeb CoreFoundation __CFRunLoopDoSources0 + 523
frame #17: 0x02418f08 CoreFoundation __CFRunLoopRun + 1032
frame #18: 0x02418846 CoreFoundation CFRunLoopRunSpecific + 470
frame #19: 0x0241865b CoreFoundation CFRunLoopRunInMode + 123
frame #20: 0x07031664 GraphicsServices GSEventRunModal + 192
frame #21: 0x070314a1 GraphicsServices GSEventRun + 104
frame #22: 0x0336ceb9 UIKit UIApplicationMain + 160
frame #23: 0x00131ed1 Oilist main + 145 at AppDelegate.swift:14
frame #24: 0x05631a25 libdyld.dylib start + 1
Your code will crash on all 32-bit platforms (such as iPhone 4, 5)
because the result of
NSDate().timeIntervalSince1970 * 1000
// E.g.: 1464850525047.38
does not fit into a 32-bit integer. As a solution, use 64-bit integers:
Int64(NSDate().timeIntervalSince1970 * 1000)
Alternatively, if the intention is to create a string representing
the milliseconds, use string formatting instead of an integer conversion:
String(format:"%.0f", NSDate().timeIntervalSince1970 * 1000)
I wanted to confirm that the following functionality is supported:
I have a simple app where I am trying to send an array of strings to UIActivityViewController. The array contains an attributed string and also a regular string. When I click on the share button and open the Mail app, I get a crash and error. However when I only send the attributed string by itself, it works.
I have tried this on IOS6 and it works fine on that.
Here is the configuration:
NSAttributedString *appName=[[NSAttributedString alloc] initWithString:#"TasteBank\n"
attributes:#{NSFontAttributeName : [UIFont boldSystemFontOfSize:[UIFont
systemFontSize]],NSForegroundColorAttributeName:[UIColor brownColor]}];
//crash seen when #"test" added to array without that no crash when mail app opened on ios7
NSMutableArray *dataToShare = [[NSMutableArray alloc ] initWithObjects: appName, #"test", nil];
UIActivityViewController* activityViewController =
[[UIActivityViewController alloc] initWithActivityItems:dataToShare applicationActivities:nil];
[self presentViewController:activityViewController animated:YES completion:^{}];
IS there something wrong with this? Is this configuration supported in IOS7? if so, could this be a bug?
I see the following error when I run on my iPhone 4 with IOS 7:
2013-10-17 11:43:50.609 testing12[2499:60b] -[NSConcreteMutableAttributedString appendString:]: unrecognized selector sent to instance 0x165ae670
2013-10-17 11:43:50.612 testing12[2499:60b] Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConcreteMutableAttributedString appendString:]: unrecognized selector sent to instance 0x165ae670'
First throw call stack:
(0x2ff53f53 0x3a32c6af 0x2ff578e7 0x2ff561d3 0x2fea5598 0x32c389a1 0x328e2f2b 0x328e2bb1 0x328e2791 0x328e23b7 0x328e20dd 0x3284c101 0x3284c101 0x326f9601 0x326f468d 0x326c9a25 0x326c8221 0x2ff1f18b 0x2ff1e65b 0x2ff1ce4f 0x2fe87ce7 0x2fe87acb 0x34ba8283 0x32729a41 0xbd1ed 0x3a834ab7)
I see this error when run on IOS7.0 simulator in XCODE 5:
2013-10-17 11:23:42.054 testing12[3258:a0b] -[NSConcreteMutableAttributedString appendString:]: unrecognized selector sent to instance 0xa181470
2013-10-17 11:23:42.085 testing12[3258:a0b] Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConcreteMutableAttributedString appendString:]: unrecognized selector sent to instance 0xa181470'
First throw call stack:
(0 CoreFoundation 0x017345e4 exceptionPreprocess + 180
1 libobjc.A.dylib 0x014b78b6 objc_exception_throw + 44
2 CoreFoundation 0x017d1903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x0172490b forwarding___ + 1019
4 CoreFoundation 0x017244ee _CF_forwarding_prep_0 + 14
5 UIKit 0x008bdfa3 -[UIMailActivity prepareWithActivityItems:] + 2346
6 UIKit 0x008b9242 -[UIActivityViewController _executeActivity] + 424
7 UIKit 0x008ba824 -[UIActivityViewController _performActivity:] + 1359
8 libobjc.A.dylib 0x014c981f -[NSObject performSelector:withObject:] + 70
9 UIKit 0x0063c75a -[UIActivityGroupViewController collectionView:didSelectItemAtIndexPath:] + 148
10 UIKit 0x0083929b -[UICollectionView _selectItemAtIndexPath:animated:scrollPosition:notifyDelegate:] + 605
11 UIKit 0x008516d8 -[UICollectionView _userSelectItemAtIndexPath:] + 189
12 UIKit 0x00851895 -[UICollectionView touchesEnded:withEvent:] + 437
13 libobjc.A.dylib 0x014c9874 -[NSObject performSelector:withObject:withObject:] + 77
14 UIKit 0x00382f92 forwardTouchMethod + 271
15 UIKit 0x00383002 -[UIResponder touchesEnded:withEvent:] + 30
16 libobjc.A.dylib 0x014c9874 -[NSObject performSelector:withObject:withObject:] + 77
17 UIKit 0x00382f92 forwardTouchMethod + 271
18 UIKit 0x00383002 -[UIResponder touchesEnded:withEvent:] + 30
19 UIKit 0x0059dd7f _UIGestureRecognizerUpdate + 7166
20 UIKit 0x00268d4a -[UIWindow _sendGesturesForEvent:] + 1291
21 UIKit 0x00269c6a -[UIWindow sendEvent:] + 1030
22 UIKit 0x0023da36 -[UIApplication sendEvent:] + 242
23 UIKit 0x00227d9f _UIApplicationHandleEventQueue + 11421
24 CoreFoundation 0x016bd8af CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
25 CoreFoundation 0x016bd23b __CFRunLoopDoSources0 + 235
26 CoreFoundation 0x016da30e __CFRunLoopRun + 910
27 CoreFoundation 0x016d9b33 CFRunLoopRunSpecific + 467
28 CoreFoundation 0x016d994b CFRunLoopRunInMode + 123
29 GraphicsServices 0x036859d7 GSEventRunModal + 192
30 GraphicsServices 0x036857fe GSEventRun + 104
31 UIKit 0x0022a94b UIApplicationMain + 1225
32 testing12 0x00002efd main + 141
33 libdyld.dylib 0x01d70725 start + 0
34 ??? 0x00000001 0x0 + 1
)
I don't know if this will help but I fixed my problem with a custom activity provider that just gave a NSString to email types and the attributed string to all the others. The email controller autodetected that the string was HTML and formatted it correctly anyway.
I guess if you can get the same effect from HTML that you can with your attributed string this might help?
#implementation ProductActivityItemProvider
...
- (id)placeholderItem {
return [[NSAttributedString alloc] initWithString:#""];
}
- (NSString *)activityViewController:(UIActivityViewController *)activityViewController subjectForActivityType:(NSString *)activityType {
if ([activityType isEqualToString:UIActivityTypeMail])
return [NSString stringWithFormat:#"I shared %#", self.product.title];
return nil;
}
- (id)item {
NSString *raw = [NSString stringWithFormat:#"<html><body>%#<br />%#<br /><b>%#</b></body></html>",
self.product.designer,
self.product.title,
self.product.price];
// The mail controller will (a) autodetect HTML and (b) crash if it's given an attributed string. sigh.
if ([self.activityType isEqualToString:UIActivityTypeMail])
return raw;
NSData *data = [raw dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *options = #{
NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute : #(NSUTF8StringEncoding)
};
NSAttributedString *text = [[NSAttributedString alloc] initWithData:data
options:options
documentAttributes:nil
error:nil];
return text;
}
#end
Got some fast solution here. Just implement a category:
#implementation NSMutableAttributedString (append)
-(void)appendString:(id)string{
if([string isKindOfClass:[NSString class]]){
[self appendAttributedString:[[NSAttributedString alloc] initWithString:string]];
}else if ([string isKindOfClass:[NSAttributedString class]]){
[self appendAttributedString:string];
}
}
#end
My stacktrace is related to maps..
NSGenericException occurs, if we try modify the array, which is being enumerated... I have taken-care about not modifying the enumerating Array.
for (int k=0;k<[[af factsArray] count];k++)
//here af is my object
{
Facts *f = [[af factsArray] objectAtIndex:k];
//here i'm removing unecessary characters from my point String
NSCharacterSet *doNotWant = [NSCharacterSet characterSetWithCharactersInString:#"POINT()"];
NSString *pointsStr = [[[f.factPosition mutableCopy] componentsSeparatedByCharactersInSet:doNotWant] componentsJoinedByString:#""];
NSArray *pieces = [[pointsStr componentsSeparatedByString:#" "] copy];
CGPoint point = CGPointMake([[pieces objectAtIndex:2] floatValue], [[pieces objectAtIndex:1] floatValue]);
NSValue *val = [NSValue valueWithCGPoint:point];
[routePointsArray addObject:val];
}
NSInteger pointsCount = routePointsArray.count;
CLLocationCoordinate2D pointsToUse[pointsCount];
for(int i = 0; i < pointsCount; i++)
{
CGPoint p = [[routePointsArray objectAtIndex:i] CGPointValue];
pointsToUse[i] = CLLocationCoordinate2DMake(p.x,p.y);
}
MKPolyline *myPolyline = [MKPolyline polylineWithCoordinates:pointsToUse count:pointsCount];
[routeOverlays addObject:myPolyline];
NSLog(#"routeOverlays count:%d",[routeOverlays count]);
//adding overlays
dispatch_async(dispatch_get_main_queue(), ^{
[self.map addOverlays:routeOverlays];
});
Can anybody tell me the problem with the code because it crashes sometimes and sometimes doesn't.
here is my stacktrace
*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x12a9f7d0> was mutated while being enumerated.'
*** First throw call stack:
(
0 CoreFoundation 0x01a2f5e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x017b28b6 objc_exception_throw + 44
2 CoreFoundation 0x01abf3b5 __NSFastEnumerationMutationHandler + 165
3 VectorKit 0x04029d7e -[VKMapModel layoutScene:withContext:] + 3854
4 VectorKit 0x0401fc8e -[VKModelObject layoutSceneIfNeeded:withContext:] + 110
5 VectorKit 0x04028bff -[VKMapModel layoutSceneIfNeeded:withContext:] + 143
6 VectorKit 0x0401fd35 -[VKModelObject layoutSceneIfNeeded:withContext:] + 277
7 VectorKit 0x0403f278 -[VKWorld layoutScene:withContext:] + 56
8 VectorKit 0x0402eac6 -[VKScreenCanvas drawWithTimestamp:] + 358
9 VectorKit 0x04019c15 -[VKMapCanvas drawWithTimestamp:] + 149
10 VectorKit 0x0402e4ee -[VKScreenCanvas onTimerFired:] + 142
11 libobjc.A.dylib 0x017c481f -[NSObject performSelector:withObject:] + 70
12 VectorKit 0x041adbdc -[VGLDisplayLink _displayLinkFired:] + 60
13 QuartzCore 0x045f3fca _ZN2CA7Display15DisplayLinkItem8dispatchEv + 48
14 QuartzCore 0x045f3e86 _ZN2CA7Display11DisplayLink14dispatch_itemsEyyy + 310
15 QuartzCore 0x045f43ab _ZN2CA7Display16TimerDisplayLink8callbackEP16__CFRunLoopTimerPv + 123
16 CoreFoundation 0x019edc46 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22
17 CoreFoundation 0x019ed62d __CFRunLoopDoTimer + 1181
18 CoreFoundation 0x019d5698 __CFRunLoopRun + 1816
19 CoreFoundation 0x019d4b33 CFRunLoopRunSpecific + 467
20 CoreFoundation 0x019d494b CFRunLoopRunInMode + 123
21 GraphicsServices 0x02c469d7 GSEventRunModal + 192
22 GraphicsServices 0x02c467fe GSEventRun + 104
23 UIKit 0x0031894b UIApplicationMain + 1225
24 SnapTraq 0x0002029d main + 141
25 libdyld.dylib 0x022c1725 start + 0
)
libc++abi.dylib: terminating with uncaught exception of type NSException
I would like to thank #micantox for his attempt to solve my problem...
Anyways, I have solved my own problem.
I was trying to execute the loop from different threads.. that caused the actual problem.
one thread is add the annotations using the NSArray and other thread is removing those NSArray objects. to avoid this problem i have used
#synchronized(self)
{
// your code goes here
}
I'm getting a crash that I am completely stumped on, when releasing a CGPath object. The crash is occurring in the CoreTextHyperlinkView library at the end of the - (void)drawInContext:(CGContextRef)ctx bounds:(CGRect)bounds method in the JSCoreTextView class.
Basically it's using Core Graphics/Text to draw underlined text. It creates a path, draws it, then releases it.
Here is the relevant stack trace:
Thread 0 Crashed:
0 CoreFoundation 0x319058b6 _CFArrayGetValueAtIndex + 2
1 MyApp 0x00300891 -[JSCoreTextView drawInContext:bounds:] (JSCoreTextView.m:678)
2 MyApp 0x00300c5f -[JSCoreTextView drawRect:] (JSCoreTextView.m:709)
3 UIKit 0x337ded61 -[UIView(CALayerDelegate) drawLayer:inContext:] + 365
4 QuartzCore 0x3358f315 -[CALayer drawInContext:] + 113
5 QuartzCore 0x3358e8c3 CABackingStoreUpdate_ + 1779
6 QuartzCore 0x3358e037 CA::Layer::display_() + 975
7 QuartzCore 0x335850b7 CA::Layer::display_if_needed(CA::Transaction*) + 203
8 QuartzCore 0x33584fe1 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 25
9 QuartzCore 0x335849c3 CA::Context::commit_transaction(CA::Transaction*) + 239
10 QuartzCore 0x335847d5 CA::Transaction::commit() + 317
11 QuartzCore 0x33584639 CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 61
12 CoreFoundation 0x3199b941 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 21
13 CoreFoundation 0x31999c39 __CFRunLoopDoObservers + 277
14 CoreFoundation 0x31999f93 __CFRunLoopRun + 747
15 CoreFoundation 0x3190d23d _CFRunLoopRunSpecific + 357
16 CoreFoundation 0x3190d0c9 _CFRunLoopRunInMode + 105
17 GraphicsServices 0x354ec33b _GSEventRunModal + 75
18 UIKit 0x338292b9 _UIApplicationMain + 1121
19 MyApp 0x0003fad7 main (main.m:13)
It seems like some array internal the the CGPath is causing the problem. Could this just be a Core Text or Core Graphics bug in iOS? I'm stuck as to how to go about investigating further as I can't look into the source code of the iOS SDK.
We only use this view in a modified BlockAlertView like this below example. We're getting the text from our JSON API in either english or arabic, which may contain email addresses or URLs to be underlineed and linkified.
JSCoreTextView *coreTextView = [[JSCoreTextView alloc] initWithFrame:CGRectMake(kAlertViewBorder, _height, frame.size.width-kAlertViewBorder*2, size.height)];
coreTextView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
coreTextView.delegate = self;
coreTextView.text = message;
coreTextView.textColor = _messageColor;
coreTextView.textAlignment = kCTCenterTextAlignment;
coreTextView.fontName = _messageFont.fontName;
coreTextView.fontSize = _messageFont.pointSize;
coreTextView.linkColor = _messageColor;
coreTextView.highlightedLinkColor = _messageLinkColor;
coreTextView.highlightColor = _messageColor;
coreTextView.backgroundColor = UIColor.clearColor;
coreTextView.underlined = YES;
[_view addSubview:coreTextView];
What is differance between the UIAlertView's from IOS 5 to IOS 6. In My IOS 6 all server side validation messages are not working..if We click on the Alert Button App is crash. I need Help On this.
(lldb) bt:(after bt got this log)
* thread #1: tid = 0x1c03, 0x0294209b libobjc.A.dylib`objc_msgSend + 15, stop reason = EXC_BAD_ACCESS (code=1, address=0x80000008)
frame #0: 0x0294209b libobjc.A.dylib`objc_msgSend + 15
frame #1: 0x01fc9020 UIKit`-[UIAlertView(Private) _buttonClicked:] + 294
frame #2: 0x02944705 libobjc.A.dylib`-[NSObject performSelector:withObject:withObject:] + 77
frame #3: 0x01bd9920 UIKit`-[UIApplication sendAction:to:from:forEvent:] + 96
frame #4: 0x01bd98b8 UIKit`-[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
frame #5: 0x01c9a671 UIKit`-[UIControl sendAction:to:forEvent:] + 66
frame #6: 0x01c9abcf UIKit`-[UIControl(Internal) _sendActionsForEvents:withEvent:] + 578
frame #7: 0x01c99d38 UIKit`-[UIControl touchesEnded:withEvent:] + 546
frame #8: 0x01c0933f UIKit`-[UIWindow _sendTouchesForEvent:] + 846
frame #9: 0x01c09552 UIKit`-[UIWindow sendEvent:] + 273
frame #10: 0x01be73aa UIKit`-[UIApplication sendEvent:] + 436
frame #11: 0x01bd8cf8 UIKit`_UIApplicationHandleEvent + 9874
frame #12: 0x035fedf9 GraphicsServices`_PurpleEventCallback + 339
frame #13: 0x035fead0 GraphicsServices`PurpleEventCallback + 46
frame #14: 0x02e89bf5 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
frame #15: 0x02e89962 CoreFoundation`__CFRunLoopDoSource1 + 146
frame #16: 0x02ebabb6 CoreFoundation`__CFRunLoopRun + 2118
frame #17: 0x02eb9f44 CoreFoundation`CFRunLoopRunSpecific + 276
frame #18: 0x02eb9e1b CoreFoundation`CFRunLoopRunInMode + 123
frame #19: 0x035fd7e3 GraphicsServices`GSEventRunModal + 88
frame #20: 0x035fd668 GraphicsServices`GSEventRun + 104
frame #21: 0x01bd665c UIKit`UIApplicationMain + 1211
frame #22: 0x0000255d mobiletummy`main + 125 at main.m:14
frame #23: 0x00002495 mobiletummy`start + 53
Have got the same problem. Throwing UIAlert on main thread resolved the thing for me. But on ur log stack it seems that you are already one the main thread.