I am developing an app that captures images from iDevice's camera and upload it to web service.
NO problem everything is working fine except the device's camera. Device's camera is driving my crazy. I am using below code to allow user to capture images. Sometimes camera shows preview and sometimes doesn't. Instead of preview is just shows complete darkness on screen. If I switch from rear to front camera is starts working fine. I have even trying deleting all background apps from device and clearing as much memory as I could; still no luck and I am stuck. :(
- (IBAction)addNewImage:(id)sender
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
// Take picture from camera
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
// set no to take as much pictures as user want.
imagePicker.showsCameraControls = YES;
// Show user the camera
[self presentModalViewController:imagePicker
animated:YES];
}
else
{
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:imagePicker
animated:YES];
}
}
I have a customer who had this issue. They must have selected to not allow access to the camera. We had to change the camera privacy setting for the app in Settings. When we switched that back on, no more black camera screen.
I was facing the same issue in iOS7 for around a month, After a long long head breaking code review of the entire app, i was able to identify the problem.
I was enumerating an
IBOutletCollection(UILabel) NSArray *staticLabelsCollection;
array Concurrently updating the labels texts, which got executed simultaneously on multiple threads.
[self.labelsArr enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
UILabel * label = (UILabel*)obj;
label.text=[NSString stringWithFormat:#"%d",idx+2];
}];
This created the problem of updating the UIKit elements on other than main thread.
I was able to catch the this issue by enabling the environment variable CA_DEBUG_TRANSACTIONS=1 in Xcode which generated warnings in device console
Nov 20 18:40:26 iPad2 CameraTest[1757] <Warning>: CoreAnimation: warning, deleted thread with uncommitted CATransaction; created by:
0 QuartzCore 0x32a553b3 <redacted> + 266
1 QuartzCore 0x32a55269 <redacted> + 224
2 QuartzCore 0x32a56871 <redacted> + 24
3 QuartzCore 0x32a56eed <redacted> + 40
4 QuartzCore 0x32a619ed <redacted> + 412
5 QuartzCore 0x32a6184b <redacted> + 46
6 QuartzCore 0x32a61819 <redacted> + 44
7 UIKit 0x32ddfe53 <redacted> + 86
8 CameraTest 0x000923b5 __35-[ViewController blockEnumeration:]_block_invoke + 184
9 CoreFoundation 0x305aa821 <redacted> + 92
10 libdispatch.dylib 0x3b3308eb <redacted> + 134
11 libdispatch.dylib 0x3b32fd71 <redacted> + 220
12 libdispatch.dylib 0x3b32ff59 <redacted> + 56
13 libsystem_pthread.dylib 0x3b46adbf _pthread_wqthread + 298
14 libsystem_pthread.dylib 0x3b46ac84 start_wqthread + 8
Fixing these 'uncommited CATransactions' by forcing them to run on the main thread fixed the black camera issues.
I was able to fix it by removing Option: NSEnumerationConcurrent from enumeration.
The sample app which could constantly reproduce the problem can be downloaded here
Hope the sample app could give some insight and the work around for the issue.
I had faced this issue in my app. Though I never found out the what the issue was, I rewrote my code to define a property of UIIMagePickerController type and initialize it once in the getter. Used this property to initialize the camera view :
getter:
-(UIImagePickerController *) imagePicker{
if(!_imagePicker){
_imagePicker = [[UIImagePickerController alloc] init];
_imagePicker.delegate = self;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
_imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
else{
_imagePicker.sourceType =UIImagePickerControllerSourceTypePhotoLibrary;
}
}
return _imagePicker;
}
- (IBAction)addNewImage:(id)sender{
if (self.imagePicker)
{
[self presentViewController:self.imagePicker animated:YES completion:^{}];
}
}
For some reason this got rid of the issue with preview sometimes showing a black screen
In ios7, you should set mainWindow.rootViewController = a class has kind is UIViewController. It's work for me.
If rootViewController is other, ex: UITabbarController, UINavigationController..., the black screen of camera will appear.
Related
I have a UIViewController. In this controller I programmatically create a UITextView and set its delegate as my controller. I do this because I dont want to start editing the textView when I tap it.
ViewDidLoad method
UITextView* textView = [[UITextView alloc] initWithFrame:CGRectMake(9, 10, 302, 200)];
[textView setDelegate:self];
[self.view addSubview:textView];
[textView release];
I implemented the textViewShouldBeginEditing method to return NO here to disable the keyboard from showing up.
textViewShouldBeginEditing method
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
NSLog(#"Shouldbegin");
return NO;
}
The problem that appears
When I tap the textView it works once, but if i tap it again it will crash the application without any log. The weird thing when I hold the textView and release it, it will work like I want it to work. A normal single tap on the other hand doesn't work a second time.
Edit
Single tapping quickly after each other also seems to work, so it seems that it wont work after i wait x seconds.
After some testing I found out it seems to be an iOS 5.X > bug. When running my App in a 4.3 device/simulator it works like it should. The error log on a iOS 5.1 device says the following:
Date/Time: 2012-04-17 14:00:49.497 +0200
OS Version: iPhone OS 5.1 (9B176)
Report Version: 104
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000014
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 TextInput 0x36bf69e8 TI::Favonius::BeamSearch::choose_hit_test_node(WTF::RefPtr<TI::Favonius::SearchNode> const&, WTF::RefPtr<TI::Favonius::KeyAreaNode> const&, WTF::RefPtr<TI::Favonius::SearchNode> const&, WTF::RefPtr<TI::Favonius::SearchNode> const&) + 12
1 TextInput 0x36bf6d1e TI::Favonius::BeamSearch::update_for_touch(unsigned int, WTF::PassRefPtr<TI::Favonius::KeyAreaNode>) + 602
2 TextInput 0x36bfb5c2 TI::Favonius::StrokeBuildManager::update_search_for_touch(unsigned int, int) + 66
3 TextInput 0x36bfb97c TI::Favonius::StrokeBuildManager::key_down_or_drag_hit_test_for_UI(bool, CGPoint, double, int, int, float, bool, ZT::LayoutDictionaryContext&, bool, int) + 216
4 TextInput 0x36bddf54 TIInputManagerZephyr::simulate_touches_for_input_string() + 344
5 TextInput 0x36bed8ba -[TIKeyboardInputManagerZephyr candidates] + 214
6 UIKit 0x31066616 -[UIKeyboardImpl generateAutocorrectionReplacements:] + 82
7 UIKit 0x31108a96 __71-[UITextInteractionAssistant scheduleReplacementsForRange:withOptions:]_block_invoke_0 + 370
8 UIKit 0x3110ec62 -[UITextSelectionView calculateAndShowReplacements:] + 6
9 Foundation 0x3762192c __NSFireDelayedPerform + 408
10 CoreFoundation 0x361a1a2c __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 8
11 CoreFoundation 0x361a1692 __CFRunLoopDoTimer + 358
12 CoreFoundation 0x361a0268 __CFRunLoopRun + 1200
13 CoreFoundation 0x3612349e CFRunLoopRunSpecific + 294
14 CoreFoundation 0x36123366 CFRunLoopRunInMode + 98
15 GraphicsServices 0x324e3432 GSEventRunModal + 130
16 UIKit 0x30e70e76 UIApplicationMain + 1074
I did find a solution. I don't really like working around Apple bugs but sometimes you have to. It is three steps...
1) replace the default keyboard with an invisible view
- (void)viewDidLoad
{
[super viewDidLoad];
myTextView.inputView = customKeyboard;
}
2) answer YES to allow editing
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView{
return YES;
}
3) In textViewDidChangeSelection resign the first responder to hide the cursor
- (void)textViewDidChangeSelection:(UITextView *)textView{
[textView resignFirstResponder];
}
If you don't want to start editing of UITextView when you tapped it:
UITextView* textView = ...;
textView.editable = NO;
After some testing I found out it seems to be an iOS 5.X > bug. When running my App in a 4.3 device/simulator it works like it should.
Look in my main post where i edited the logfile.
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
[txtView resignFirstResponder];
}
and release txtView in dealloc method
Swift 4.2
The best and easy way to solve this just make undo manager as false
textView.undoManager?.disableUndoRegistration()
This error appears if you have change the view at run time like within the table, and cell will be reloaded on tapping,
First, thanks in advance for taking the time to read through this. I have been searching for an answer to this issue for a few days but I cannot seem to find what I am looking for. I know that SIGSEGV errors (or EXEC_BAD_ACCESS faults) are usually caused by memory management issues but after hours of looking at the code, I can't seem to find an error. The static analyzer hasn't found anything either.
As the title says, this error only occurs on the device (never in the simulator) and doesn't happen every time the given view loads. Obviously this means that I can't use NSZombie to debug what is going wrong.
Let's start with the crash dump log:
0 myApp 0x00036659 +[TFCrashHandler backtrace] + 428
1 myApp 0x00036a6f TFSignalHandler + 54
2 libsystem_c.dylib 0x32f48539 _sigtramp + 48
3 UIKit 0x365701df -[UIView(Rendering) setNeedsDisplay] + 86
4 UIKit 0x36598269 -[UILabel setFont:] + 232
5 myApp 0x000190eb +[BruUISettings applyLabelDetailStyle:] (BruUISettings.m:130)
6 myApp 0x0001aa57 -[ActiveChallengeViewController viewDidLoad] (ActiveChallengeViewController.m:115)
7 UIKit 0x365a57ff -[UIViewController view] + 166
8 UIKit 0x365b1c39 -[UIViewController contentScrollView] + 24
9 UIKit 0x365b1aa9 -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewController:] + 36
10 UIKit 0x365b198f -[UINavigationController _layoutViewController:] + 34
11 UIKit 0x365b115b -[UINavigationController _startTransition:fromViewController:toViewController:] + 318
12 UIKit 0x365b0f53 -[UINavigationController _startDeferredTransitionIfNeeded] + 250
13 UIKit 0x365a5673 -[UINavigationController pushViewController:transition:forceImmediate:] + 806
14 UIKit 0x365a5349 -[UINavigationController pushViewController:animated:] + 36
15 myApp 0x00015dc7 -[ChallengesHomeViewController tableView:didSelectRowAtIndexPath:] (ChallengesHomeViewController.m:325)
16 UIKit 0x3661f565 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 944
17 UIKit 0x36697ce7 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 158
18 Foundation 0x31f7a943 __NSFireDelayedPerform + 414
19 CoreFoundation 0x34ab1a63 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14
20 CoreFoundation 0x34ab16c9 __CFRunLoopDoTimer + 364
21 CoreFoundation 0x34ab029f __CFRunLoopRun + 1206
22 CoreFoundation 0x34a334dd CFRunLoopRunSpecific + 300
23 CoreFoundation 0x34a333a5 CFRunLoopRunInMode + 104
24 GraphicsServices 0x351a7fed GSEventRunModal + 156
25 UIKit 0x3659a743 UIApplicationMain + 1090
26 myApp 0x000026c5 main (main.m:13)
27 myApp 0x0000265c start + 52
Note, I am using TestFlight from testflightapp.com and it is there exception handler at the top of the stack.
Here is the code that is creating and pushing the view controller in question:
CDAcceptedChallenge *challengeAtIndex = [self.activeChallenges objectAtIndex:[indexPath row]];
ActiveChallengeViewController *view = [[ActiveChallengeViewController alloc] initWithNibName:#"ActiveChallengeViewController"
bundle:nil
activeChallenge:challengeAtIndex];
view.leaveChallengeTarget = self;
[self.navigationController pushViewController:view animated:YES];
[view release];
This code is running inside of a didSelectRowAtIndex method, if that matters at all. This view controller has a bunch of member variables and IBOutlets which reference objects in the nib but here are the ones that correlate to the object mentioned in this error:
in .h:
UILabel *helpLabel;
...
#property (nonatomic, retain) IBOutlet UILabel *helpLabel;
in .m:
#synthesize helpLabel;
I am positive that helpLabel is bound to the correct object in the nib because it does get the correct styling when this doesn't blow up. Next, here is the init method for this view controller:
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
self.activeChallenge = inActiveChallenge;
}
return self;
Here is the viewDidLoad method where we will sometimes see the crash (bolded). Note, there is a lot going on here but nothing touches the self.helpLabel which is what eventually triggers the crash.
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:FALSE];
self.navigationItem.title = #"Details";
// overlay disclosure creation
self.overlayDisclosure = [CustomColoredDisclosureIndicator accessoryWithColor:self.challengeNameLabel.textColor];
self.overlayDisclosure.highlightedColor = [UIColor whiteColor];
[self.overlayDisclosure addTarget:self action:#selector(overlayViewButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.overlayDisclosure];
[[BruNotificationManager instance] registerForTabUpdated:[[[BruCallback alloc] initWithTarget:self
andCallback:#selector(tabUpdated:)] autorelease]];
[[BruNotificationManager instance] registerForActiveChallengesUpdated:[BruCallback buildFromObject:self
andCallback:#selector(challengesUpdatedLocally)]];
[[BruNotificationManager instance] registerForEarnedRewardsUpdated:[BruCallback buildFromObject:self
andCallback:#selector(rewardsUpdatedLocally:)]];
[super refreshEarnedRewardsForChallenge:self.activeChallenge.challenge.identifier];
[super refreshTabForChallenge:self.activeChallenge.challenge.identifier];
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:#selector(addBeer)];
self.navigationItem.rightBarButtonItem = addButton;
[addButton release];
// Request that the object download its image
BruCallback *imageCallback = [BruCallback buildFromObject:self andCallback:#selector(imageRequestCompleted:withData:)];
self.challengeImageView.image = [self.activeChallenge.challenge retrieveImage:self.bruConnection withCallback:imageCallback];
// Create our help label
**[BruUISettings applyLabelDetailStyle:self.helpLabel];**
self.helpLabel.textColor = AccentSecondaryColor;
self.overlayView.alpha = [BruUISettings standardOverlayViewAlpha];
[BruUISettings applyTableStyle:self.rewardsTable];
[BruUISettings applyScrollViewStyle:self.scrollView];
self.needToUpdateTab = YES;
self.needToUpdateRewards = YES;
self.needToUpdateChallenge = NO;
Here is a trimmed down version of the viewDidUnload method, though I don't see why it would matter in this case:
...
self.helpLabel = nil;
...
[super viewDidUnload];
Finally, my [BruUISettings applyLabelDetailStyle] is a method that applies a centralized style to my label. There are a bunch of places in my code that use this function so that I can change all of the styles for those labels by just changing the one function.
+ (void) applyLabelDetailStyle:(UILabel *)inLabel
{
inLabel.font = [UIFont fontWithName:#"Helvetica Neue" size:12.0];
inLabel.textColor = [UIColor darkGrayColor];
inLabel.backgroundColor = [UIColor clearColor];
}
Any thoughts as to what could be happening here would be greatly appreciated. Thanks again.
After a lot of debugging I found that this was actually due to a memory corruption being caused by the QSStrings library which I was using to generate base64 encoded strings. The crashes seemed to happen randomly but only after this library was invoked. When I switched to a different MD5 library, the issue went away. If you are using this library, I would suggest finding a new one to do base64 encoding. I moved to the one found here: http://www.cocoadev.com/index.pl?BaseSixtyFour
I think the problem happens because you have something wrong in your view that owns your label (view of your ActiveChallengeViewController).
When you set the font of your label, that invokes the setNeedsDisplay of your parent view and because something is wrong, setNeedsDisplay crashs.
Your line :
self.challengeImageView.image = [self.activeChallenge.challenge retrieveImage:self.bruConnection withCallback:imageCallback];
Is it a synchronous connection to retrieve the image ?
Maybe the problem happen here when sometimes the image isn't retrieved from your connection and so the image property of your image view is bad.
But i am not sure because setNeedsDisplay doesn't directly invoke the redraw of the view so i don't know if the debugger catches the error just the after setNeedsDisplay call.
Edit :
I think this answer is bad, if image is not ok, the crash must happen when the imageView image property retains the image but i let the answer in the case of it could help you to point to the real problem.
Edit: This was all caused by a typo in my Other Link Flags setting. See my answer below for more information.
I'm attempting to mock a UIWebView so that I can verify that methods on it are called during a test of an iOS view controller. I'm using an OCMock static library built from SVN revision 70 (the most recent as of the time of this question), and Google Toolbox for Mac's (GTM) unit testing framework, revision 410 from SVN. I'm getting the following error when the view controller attempts to call the expected method.
Test Case '-[FirstLookViewControllerTests testViewDidLoad]' started.
2010-11-11 07:32:02.272 Unit Test[38367:903] -[NSInvocation getArgumentAtIndexAsObject:]: unrecognized selector sent to instance 0x6869ea0
2010-11-11 07:32:02.277 Unit Test[38367:903] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSInvocation getArgumentAtIndexAsObject:]: unrecognized selector sent to instance 0x6869ea0'
*** Call stack at first throw:
(
0 CoreFoundation 0x010cebe9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x012235c2 objc_exception_throw + 47
2 CoreFoundation 0x010d06fb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x01040366 ___forwarding___ + 966
4 CoreFoundation 0x0103ff22 _CF_forwarding_prep_0 + 50
5 Unit Test 0x0000b29f -[OCMockRecorder matchesInvocation:] + 216
6 Unit Test 0x0000c1c1 -[OCMockObject handleInvocation:] + 111
7 Unit Test 0x0000c12a -[OCMockObject forwardInvocation:] + 43
8 CoreFoundation 0x01040404 ___forwarding___ + 1124
9 CoreFoundation 0x0103ff22 _CF_forwarding_prep_0 + 50
10 Unit Test 0x0000272a -[MyViewController viewDidLoad] + 100
11 Unit Test 0x0000926c -[MyViewControllerTests testViewDidLoad] + 243
12 Unit Test 0x0000537f -[SenTestCase invokeTest] + 163
13 Unit Test 0x000058a4 -[GTMTestCase invokeTest] + 146
14 Unit Test 0x0000501c -[SenTestCase performTest] + 37
15 Unit Test 0x000040c9 -[GTMIPhoneUnitTestDelegate runTests] + 1413
16 Unit Test 0x00003a87 -[GTMIPhoneUnitTestDelegate applicationDidFinishLaunching:] + 197
17 UIKit 0x00309253 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1252
18 UIKit 0x0030b55e -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 439
19 UIKit 0x0030aef0 -[UIApplication _run] + 452
20 UIKit 0x0031742e UIApplicationMain + 1160
21 Unit Test 0x0000468c main + 104
22 Unit Test 0x000026bd start + 53
23 ??? 0x00000002 0x0 + 2
)
terminate called after throwing an instance of 'NSException'
/Users/gjritter/src/google-toolbox-for-mac-read-only/UnitTesting/RunIPhoneUnitTest.sh: line 151: 38367 Abort trap "$TARGET_BUILD_DIR/$EXECUTABLE_PATH" -RegisterForSystemEvents
My test code is:
- (void)testViewDidLoad {
MyViewController *viewController = [[MyViewController alloc] init];
id mockWebView = [OCMockObject mockForClass:[UIWebView class]];
[[mockWebView expect] setDelegate:viewController];
viewController.webView = mockWebView;
[viewController viewDidLoad];
[mockWebView verify];
[mockWebView release];
}
My view controller code is:
- (void)viewDidLoad {
[super viewDidLoad];
webView.delegate = self;
}
I did find that the test would run successfully if I instead used:
- (void)testViewDidLoad {
MyViewController *viewController = [[MyViewController alloc] init];
id mockWebView = [OCMockObject partialMockForObject:[[UIWebView alloc] init]];
//[[mockWebView expect] setDelegate:viewController];
viewController.webView = mockWebView;
[viewController viewDidLoad];
[mockWebView verify];
[mockWebView release];
}
However, as soon as I added the expectation that is commented out, the error returned when using the partial mock.
I have other tests that are successfully using mocks in the same project.
Any ideas? Is mocking of UIKit objects supported by OCMock?
Edit: Based on advice in the answer below, I tried the following test, but I'm getting the same error:
- (void)testViewDidLoadLoadsWebView {
MyViewController *viewController = [[MyViewController alloc] init];
UIWebView *webView = [[UIWebView alloc] init];
// This test fails in the same fashion with or without the next line commented
//viewController.view;
id mockWebView = [OCMockObject partialMockForObject:webView];
// When I comment out the following line, the test passes
[[mockWebView expect] loadRequest:[OCMArg any]];
viewController.webView = mockWebView;
[viewController viewDidLoad];
[mockWebView verify];
[mockWebView release];
}
UIKit classes are mysterious beasts, and I've found that mucking around with mocking them can lead to hours of debugging fun. That said, I've found that with a little patience you can make it work.
The first thing I notice with your code is that your controller doesn't load its view in your test. I generally make sure to always force the view to load before any tests run. That, of course, means you can't write expectations for the initialization of your web view, but in this case you don't really need to. You could do this:
- (void)testViewDidLoadSetsWebViewDelegateToSelf {
MyViewController *viewController = [[MyViewController alloc] init];
// Force the view to load
viewController.view;
assertThat(controller.webView.delegate, equalTo(controller));
}
That said, if you do want to then subsequently mock the web view, I would recommend using a partial mock for the existing web view:
- (void)testWebViewDoesSomething {
MyViewController *viewController = [[MyViewController alloc] init];
// Force the view to load
viewController.view;
id mockWebView = [OCMockObject partialMockForObject:controller.webView];
[[mockWebView expect] someMethod];
[controller doWhatever];
[mockWebView verify];
}
In fact, I've found it's best to always use a partial mock for any UIView subclass. If you create a full mock of a UIView it will almost always blow up messily when you try to do something view-related with it, such as add it to a superview.
This turned out to be one of those off by one character issues that you don't notice until you've looked at it a few dozen times.
Per this post on the OCMock forums, I had set my Other Linker Flags for my unit test target to -ObjC -forceload $(PROJECT_DIR)/Libraries/libOCMock.a. This is wrong; -forceload should have been -force_load. Once I fixed this typo, my tests worked.
I grabbed the crash log from the iPhone:
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x0000000c
Crashed Thread: 0
Thread 0 Crashed:
0 libobjc.A.dylib 0x30011940 objc_msgSend + 20
1 CoreFoundation 0x30235f1e CFRelease + 98
2 UIKit 0x308f4974 -[UIImage dealloc] + 36
3 CoreFoundation 0x30236b72 -[NSObject release] + 28
4 UIKit 0x30a00298 FlushNamedImage + 64
5 CoreFoundation 0x30250a20 CFDictionaryApplyFunction + 124
6 UIKit 0x30a0019c _UISharedImageFlushAll + 196
7 UIKit 0x30a00730 +[UIImage(UIImageInternal) _flushCacheOnMemoryWarning:] + 8
8 Foundation 0x3054dc7a _nsnote_callback + 178
9 CoreFoundation 0x3024ea52 _CFXNotificationPostNotification + 298
10 Foundation 0x3054b854 -[NSNotificationCenter postNotificationName:object:userInfo:] + 64
11 Foundation 0x3054dbba -[NSNotificationCenter postNotificationName:object:] + 14
12 UIKit 0x30a00708 -[UIApplication _performMemoryWarning] + 60
13 UIKit 0x30a006a0 -[UIApplication _receivedMemoryNotification] + 128
14 UIKit 0x30a005d0 _memoryStatusChanged + 56
15 CoreFoundation 0x30217410 __CFNotificationCenterDarwinCallBack + 20
16 CoreFoundation 0x3020d0aa __CFMachPortPerform + 72
17 CoreFoundation 0x30254a70 CFRunLoopRunSpecific + 2296
18 CoreFoundation 0x30254164 CFRunLoopRunInMode + 44
19 GraphicsServices 0x3204529c GSEventRunModal + 188
20 UIKit 0x308f0374 -[UIApplication _run] + 552
21 UIKit 0x308eea8c UIApplicationMain + 960
...
...
From my previous question, Can somebody give me a hand about this stacktrace in iPhone app?, I have changed my codes mainly around UIImage part. I now use [[UIImage alloc] initWithContentsOfFile ... ]. No more [UIImage imageNamed: ... ] or the like. The portion is below.
//this is a method of a subclass of UIImageView.
- (void) reviewImage: (bool) review{
NSString* st;
if (review){
NSString* origin = [NSString stringWithString: [[ReviewCardManager getInstance] getCardImageString:chosenIndex]];
NSString* stt = [origin substringToIndex: [origin length]-4];
st = [[NSString alloc] initWithString: stt];
if (myImageFlipped == nil)
myImageFlipped = [[UIImage alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForResource:st ofType:#"png"]];
[self setImage:myImageFlipped];
if (notRotated){
self.transform = CGAffineTransformRotate(self.transform, [MyMath radf:rotate]);
notRotated = false;
}
}else{
st = [[NSString alloc] initWithFormat:#"sc%d", chosenNumber];
if (myImage == nil)
myImage = [[UIImage alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForResource:st ofType:#"png"]];
[self setImage:myImage];
if (notRotated){
self.transform = CGAffineTransformRotate(self.transform, [MyMath radf:rotate]);
notRotated = false;
}
}
[st release];
}
I also have the UIImage already retained in the property.
#property (nonatomic, retain) UIImage* myImage, *myImageFlipped;
Memory Leaks have also been taken cared of. These variables are release in dealloc method.
I thought that I have successfully killed the bug, but it seems that I still have a rare occuring bug problem.
Based on the crash log, my application yells out "performMemoryWarning". I am just "alloc"-ing 13 .png images with the size 156 x 272. I'm confused. Those images shouldn't take that much memory to the point that it exceeds iPhone's RAM. Or is there something I am overlooking? Please advise.
To help you with memory issues and UIImages, you might want to use the imageNamed convience method of UIImage, from the docs:
This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.
Alternatively, you might want to go this route if you still run into memory issues after switching to UIImage imageNamed, because there are some downsides to using the convinience method.
The problem is solved. I forgot to change UIImage at one place. Now, all UIImages are truly "alloc", no more autorelease.
FYI, if you are using [UIImage imageNamed: ... ], use "Simulate Memory Warning" on iPhone Simulator to see whether you are having a problem with it when the real device is low on memory.
I'm currently writing an Iphone application using Core Data and I get a EXC_BAD_ACCESS error during the [managedObjectContext save:&&error] code line. This crash only happens after I modify certain fields. More specifically my entity has two string fields (out of about 10 fields), that get their values from a the return of a modal view controller (like a text editor). The crash also only happens after these fields are edited, the first time I put a value in it works fine.
The reason I have string with format constructors with just strings is because I was trying to copy construct... not sure if that happens automatically? Thought maybe retain/release messages from those strings (those two are from the modal view controller), were getting released on dismissal of the modal view controller or something. Guess not though because it still doesn't work.
Here's the code section that is crashing:
[EDITED]
- (void)actionSheet:(UIActionSheet *)modalView clickedButtonAtIndex: (NSInteger)buttonIndex
switch(buttonIndex) {
case 0: {
if(message == nil) {
message = [NSEntityDescription insertNewObjectForEntityForName:#"MailMessage" inManagedObjectContext:self.managedObjectContext];
}
message.toString = txtTo.text;
message.fromString = txtFrom.text;
message.subjectString = txtSubject.text;
message.backgroundColor = [NSNumber numberWithInt:[bgColor intValue]];
message.textArray = [NSString stringWithFormat:#"%#", stringTextArray];
message.htmlString = [NSString stringWithFormat:#"%#", stringHTML];
message.timeStamp = [NSDate date];
message.statusCode = [NSNumber numberWithInt:0];
NSError *error = nil;
if (![message.managedObjectContext save:&error]) {
abort();
}
break;
}
case 1: {
break;
}
}
if(buttonIndex != modalView.cancelButtonIndex) {
[webViewBody loadHTMLString:#"<html><head></head><body></body></html>" baseURL:[NSURL URLWithString:#""]];
[self.navigationController popToRootViewControllerAnimated:YES];
}
}
And here's the crash log:
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x00000015
Crashed Thread: 0
Thread 0 Crashed:
0 libobjc.A.dylib 0x30011940 objc_msgSend + 20
1 CoreData 0x367f7d3e -[NSKnownKeysDictionary1 dealloc] + 82
2 CoreData 0x367f7cda -[NSKnownKeysDictionary1 release] + 34
3 CoreData 0x3687eec4 -[NSManagedObject(_NSInternalMethods) _setOriginalSnapshot__:] + 40
4 CoreData 0x36821030 -[NSManagedObjectContext(_NSInternalAdditions) _clearOriginalSnapshotAndInitializeRec:] + 16
5 CoreData 0x368205f2 -[NSManagedObjectContext(_NSInternalAdditions) _didSaveChanges] + 958
6 CoreData 0x368133bc -[NSManagedObjectContext save:] + 412
7 Decome 0x0001fdd6 -[CreateMessageViewController actionSheet:clickedButtonAtIndex:] (CreateMessageViewController.m:163)
8 UIKit 0x30a6cbd8 -[UIActionSheet(Private) _buttonClicked:] + 256
9 CoreFoundation 0x30256dd4 -[NSObject performSelector:withObject:withObject:] + 20
10 UIKit 0x3096e0d0 -[UIApplication sendAction:to:from:forEvent:] + 128
11 UIKit 0x3096e038 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 32
12 UIKit 0x3096e000 -[UIControl sendAction:to:forEvent:] + 44
13 UIKit 0x3096dc58 -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 528
14 UIKit 0x309a6e9c -[UIControl touchesEnded:withEvent:] + 452
15 UIKit 0x309a60d4 -[UIWindow _sendTouchesForEvent:] + 520
16 UIKit 0x309a5464 -[UIWindow sendEvent:] + 108
17 UIKit 0x30936e3c -[UIApplication sendEvent:] + 400
Any help is appreciated, Thanks.
UPDATE: Also, even though the program crashes, when I open it back up it the data has saved correctly. So the EXC_BAD_ACCESS must happen after the save has gotten at least far enough to store in the persistent store i think.
If I comment out the save line, the code runs fine now. But it doesn't save after i close and exit. If I run the save line in my Root View Controllers willAppear function, it throws the same EXC_BAD_ACCESS error. The console doesn't say anything other than EXC_BAD_ACCESS
if I do a backtrace I get :
#0 0x30011940 in objc_msgSend ()
#1 0x367f7d44 in -[NSKnownKeysDictionary1 dealloc] ()
#2 0x367f7ce0 in -[NSKnownKeysDictionary1 release] ()
#3 0x3687eeca in -[NSManagedObject(_NSInternalMethods) _setOriginalSnapshot__:] ()
#4 0x36821036 in -[NSManagedObjectContext(_NSInternalAdditions) _clearOriginalSnapshotAndInitializeRec:] ()
#5 0x368205f8 in -[NSManagedObjectContext(_NSInternalAdditions) _didSaveChanges] ()
#6 0x368133c2 in -[NSManagedObjectContext save:] ()
#7 0x0000314e in -[RootViewController viewWillAppear:] (self=0x11b560, _cmd=0x3014ecac, animated=1 '\001') at /Users/inckbmj/Desktop/iphone/Decome/Classes/RootViewController.m:85
Sorry the code wasn't properly formatted before. When this view controller gets created if it is not a new "message" it is passed a message object obtained from a fetchedResultsController like so:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
MailMessage *aMessage = (MailMessage *)[fetchedResultsController objectAtIndexPath:indexPath];
[messageView loadMessage:aMessage viewOnly:NO usingTemplate:NO];
messageView.managedObjectContext = self.managedObjectContext;
[self.navigationController pushViewController:messageView animated:YES];
}
(the first set of code is from the MessageViewController.m file which is the class that messsageView is)
It only crashes if I present my EditorViewController as a modal view and then return.
Even if I change the textArray and htmlString lines (which are the only things the modal view affects) to:
message.textArray = #"HELLO";
message.htmlString = #"HELLO";
it still crashes. If I comment both lines out however it doesn't crash.
So it seems like it crashes if I present a modal view and then try to edit either the textArray or htmlString fields of my NSOManagedObject...
Here is where i present the view:
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event {
if(!viewOnly) {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView: txtTo];
location = [touch locationInView: webViewBody];
if(CGRectContainsPoint(webViewBody.bounds, location)) {
[editor loadTextArrayString:stringTextArray];
[self presentModalViewController:editor animated:YES];
}
}
}
and where i dismiss it:
-(void)returnWithTextArray:(NSString *)arrayString HTML:(NSString *)html bgColor:(NSNumber *)numColor {
[self dismissModalViewControllerAnimated:YES];
self.stringTextArray = [NSString stringWithFormat:#"%#", arrayString];
self.stringHTML = [NSString stringWithFormat:#"%#", html];
self.bgColor = [NSNumber numberWithInt:[numColor intValue]];
[webViewBody loadHTMLString:self.stringHTML baseURL:[NSURL URLWithString:#""]];
}
You are only guaranteed to retain access to a managed object from the context as long as a change is pending to that object (insert, update, delete). As soon as you make a call to save:, you can lose your reference to the managed object.
While you stopped getting the error when you set setRetainsRegisteredObjects:YES, you may have introduced a memory management issue, as you are setting the managed object's lifetime to be dependent on the lifetime of the managed object context. If you're passing your context around throughout your app, this could get rather large if you have a large object hierarchy.
You can read more in the Apple docs here: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/MO_Lifecycle.html
Solved the problem though I'm not sure I'm addressing the actual root cause. The error was eliminated when I added this line:
[managedObjectContext setRetainsRegisteredObjects:YES];
To where I create the managedObjectContext. So I guess it had to do with retain counts. I'm guessing that maybe instance variables get released partially or temporarily or something when modal views are presented? I don't know. In any case, this error was eliminated the the program works fine now.
Just to help others having the same issue, and reinforcing Steff's response above, the likely cause of this error is that you are trying to release a NSManagedObject.
I have seen many funny behaviours with CoreData on iPhone that were solved by resetting content and settings in the iPhone simulator.
I know this is an oldie but I had the same issue so thought I'd add my tuppence as to how I solved the issue, mine was caused by manually releasing the managed object within the modal view, I removed the release calls and everything is working fine :) according to the docs you shouldn't manually try and release managed objects anyway as the context will look after all of that. That's my experience anyway, search through your code for over-released values.
You must set the FRC cache to nil
I have solved a similar problem by making sure that the object is fetched, so for the example above:
if ( message == nil ) {
message = [NSEntityDescription insertNewObjectForEntityForName:#"MailMessage" inManagedObjectContext:self.managedObjectContext];
} else {
NSError *error = nil;
message = (MailMessage *)[managedObjectContext existingObjectWithID:[message objectID] error:&error];
}