iOS - 如果仅在设备上运行,我的应用程序会因内存错误而崩溃
Posted
技术标签:
【中文标题】iOS - 如果仅在设备上运行,我的应用程序会因内存错误而崩溃【英文标题】:iOS - My app crashes with memory Error if only runs on Device 【发布时间】:2015-07-30 23:19:01 【问题描述】:我的应用在模拟器上完美运行。 但是当我在设备上运行它进行测试时,应用程序崩溃了。
显示的错误:
"malloc: * 对象 0x17415d0c0 的错误:从空闲列表中出列的无效指针 * 在 malloc_error_break 中设置断点以进行调试";
有时还会发生另一个错误:
“线程6 com.apple.NSURLConnectionLoader:程序接收到的信号:EXC_BAD_ACCESS”
这两个错误是随机的,会在应用运行两三分钟后发生。
我搜索了谷歌并找到了一些解决方案。 它说在 malloc_error_break 中设置断点进行调试,但这仅适用于模拟器。即使我设置了 malloc_error_break,应用程序仍然崩溃并且它不显示任何内容,我只能看到错误消息。
这是一个大项目,我真的不知道哪部分代码导致了问题,我需要发布哪部分代码。 但我对其中一门课,我的“SynchroningView”有疑问。 如果只有我的应用程序与服务器同步,将显示此视图。这意味着这个视图包含在我项目中几乎所有的 Viewcontroller 中。
这是我的“SynchroningView”类:
“SynchroningView.h”
#import <UIKit/UIKit.h>
@class SynchroningView;
@protocol SynchroningViewDelegate
@optional
- (void)SynchroningViewCancelButtonDidClicked:(SynchroningView *)synchroningView;
- (void)SynchroningViewStartTherapyButtonDidClicked:(SynchroningView *)synchroningView;
@end
@interface SynchroningView : UIView <DataManagerDelegate>
@property (nonatomic, assign) id<SynchroningViewDelegate>delegateCustom;
@property (nonatomic, retain) UIButton *containerButton;
@property (nonatomic, retain) Patient *singlePatient;
- (instancetype)initWithFrame:(CGRect)frame;
- (void)showInView:(UIView *)view;
- (void)dismissMenuPopover;
@end
SynchroningView.m
#import "SDDemoItemView.h"
#import "SDPieLoopProgressView.h"
#define Directory_Document [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
#define FileName_Image_SynchroningView_BackGroundImageName @"SynchroningView_BackGroundImage"
#define FilePath_Image_SynchroningView_BackGroundImageName [Directory_Document stringByAppendingPathComponent:FileName_Image_SynchroningView_BackGroundImageName]
@interface SynchroningView ()
@property (nonatomic, strong) DataManager* dataManager;
@property (nonatomic, retain) UILabel* messageLabel;
@property (nonatomic, retain) UIButton* CancelButton;
@property (nonatomic, retain) CoolButton* ConfirmButton;
@property (nonatomic, retain) CoolButton* startTherapyButton;
@property (nonatomic, strong) SDDemoItemView* demoProgressView;
@end
@interface SynchroningView ()
BOOL _blinking;
NSTimer *timer;
@end
@implementation SynchroningView
-(void)dealloc
//get the background Image, make it blur and save it. In this way I do not have to use Blur function everytim, I use the blured image directly
- (UIImage *)getBackGroundImage
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:FilePath_Image_SynchroningView_BackGroundImageName])
return [UIImage imageWithContentsOfFile:FilePath_Image_SynchroningView_BackGroundImageName];
else
UIImage *backImage = [UIImage imageWithContentsOfFile:kBackgroundImagePath];
backImage = [backImage blurWithFloat:20.0f];
NSData * binaryImageData = UIImagePNGRepresentation(backImage);
if ([binaryImageData writeToFile:FilePath_Image_SynchroningView_BackGroundImageName atomically:YES])
return backImage;
return [UIImage imageWithContentsOfFile:kBackgroundImagePath];
-(instancetype)initWithFrame:(CGRect)frame
self = [super initWithFrame:frame];
if (self)
_blinking = NO;
self.dataManager = [[DataManager alloc] init];
self.dataManager.DelegateCustom = self;
self.backgroundColor = [UIColor clearColor];
self.containerButton = [[UIButton alloc] init];
[self.containerButton setBackgroundColor:RGBA_Custom(0, 0, 0, 0.6f)];
[self.containerButton setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin];
UIView *shadowView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
[self addSubview:shadowView];
shadowView.backgroundColor = RGBA_Custom(230, 249, 251, 0.96f);
// shadowView.layer.borderWidth = 2*IPAD;
// shadowView.layer.borderColor = [RGBA_Custom(199, 199, 199, 1.0f) CGColor];
shadowView.layer.shadowColor = [UIColor blackColor].CGColor;
shadowView.layer.shadowOpacity = 0.4;
shadowView.layer.shadowRadius = 4*IPAD;
shadowView.layer.shadowOffset = CGSizeMake(4.0f*IPAD, 4.0f*IPAD);
shadowView.layer.cornerRadius = 6*IPAD;
shadowView.userInteractionEnabled = NO;
UIImageView *backGround = [[UIImageView alloc] initWithImage:[self getBackGroundImage]];
backGround.frame = CGRectMake(0, 0, shadowView.frame.size.width, shadowView.frame.size.height);
backGround.backgroundColor = [UIColor clearColor];
[shadowView addSubview:backGround];
backGround.layer.cornerRadius = shadowView.layer.cornerRadius;
backGround.layer.masksToBounds = YES;
ImageWIDTH_ = self.frame.size.height*0.3;
self.demoProgressView =[SDDemoItemView demoItemViewWithClass:[SDPieLoopProgressView class]];
self.demoProgressView.frame = CGRectMake((self.frame.size.width - ImageWIDTH_)/2,
kFromLeft,
ImageWIDTH_,
ImageWIDTH_);
[self addSubview:self.demoProgressView];
self.messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(kFromLeft,
self.demoProgressView.frame.origin.y + self.demoProgressView.frame.size.height + kFromLeft,
self.frame.size.width - kFromLeft*2,
self.frame.size.height - (self.demoProgressView.frame.origin.y + self.demoProgressView.frame.size.height + kFromLeft*2))];
self.messageLabel.backgroundColor = [UIColor clearColor];
self.messageLabel.textColor = [UIColor blackColor];
self.messageLabel.textAlignment = NSTextAlignmentCenter;
self.messageLabel.numberOfLines = 0;
self.messageLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.messageLabel.font = [UIFont boldSystemFontOfSize:kIPAD ? 20:12];
self.messageLabel.text = @"";
self.messageLabel.adjustsFontSizeToFitWidth = YES;
[self addSubview:self.messageLabel];
CGFloat BtnHeight = kIPAD ? 40 : 30;
self.CancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.CancelButton.frame = CGRectMake(self.frame.size.width - kFromLeft*0.5 - BtnHeight,
kFromLeft*0.5,
BtnHeight,
BtnHeight);
self.CancelButton.backgroundColor = [UIColor clearColor];
[self.CancelButton setImage:[[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"utilities_close" ofType:@"png"]] forState:UIControlStateNormal];
[self.CancelButton addTarget:self action:@selector(pressCancelButton:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.CancelButton];
BtnHeight = kIPAD ? 70 : 50;
CGFloat BtnWidth = self.frame.size.width/4;
NSString* ConfirmButtonStr = NSLocalizedString(@"Confirm", nil);
ExpectedSize = [ConfirmButtonStr sizeWithFont:self.messageLabel.font constrainedToSize:CGSizeMake(VIEW_WIDTH, BtnHeight) lineBreakMode:NSLineBreakByWordWrapping];
ExpectedSize = CGSizeMake(ExpectedSize.width + 30*IPAD, ExpectedSize.height);
self.ConfirmButton = [CoolButton buttonWithType:UIButtonTypeCustom];
self.ConfirmButton.frame = CGRectMake((self.frame.size.width - ExpectedSize.width)/2,
self.frame.size.height - BtnHeight - kFromLeft,
ExpectedSize.width,
BtnHeight);
self.ConfirmButton.titleLabel.font = self.messageLabel.font;
[self.ConfirmButton setTitle:ConfirmButtonStr forState:UIControlStateNormal];
[self.ConfirmButton addTarget:self action:@selector(pressConfirmButton:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.ConfirmButton];
BtnWidth = self.frame.size.width*0.6;
NSString* startTherapyButtonStr = NSLocalizedString(@"StartTerapia", nil);
ExpectedSize = [startTherapyButtonStr sizeWithFont:self.messageLabel.font constrainedToSize:CGSizeMake(VIEW_WIDTH, BtnHeight) lineBreakMode:NSLineBreakByWordWrapping];
ExpectedSize = CGSizeMake(ExpectedSize.width + 30*IPAD, ExpectedSize.height);
self.startTherapyButton = [CoolButton buttonWithType:UIButtonTypeCustom];
self.startTherapyButton.frame = CGRectMake((self.frame.size.width - ExpectedSize.width)/2,
self.ConfirmButton.frame.origin.y,
ExpectedSize.width,
self.ConfirmButton.frame.size.height);
self.startTherapyButton.titleLabel.font = self.messageLabel.font;
[self.startTherapyButton setTitle:startTherapyButtonStr forState:UIControlStateNormal];
[self.startTherapyButton addTarget:self action:@selector(startTherapyButtonDidClicked:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.startTherapyButton];
self.CancelButton.alpha = 0.0;
self.ConfirmButton.alpha = 0.0;
self.startTherapyButton.alpha = 0.0;
if (self.dataManager.firstSynchronizationAgain == 1 && [AccessedInfo getAccessedInfo])
UILabel *alertInfoLabel = [[UILabel alloc] initWithFrame:CGRectMake(kFromLeft,
0,
self.frame.size.width - kFromLeft*2,
VIEW_HEIGHT)];
alertInfoLabel.backgroundColor = [UIColor clearColor];
alertInfoLabel.textColor = COLOR_CIRCLE;
alertInfoLabel.textAlignment = NSTextAlignmentCenter;
alertInfoLabel.numberOfLines = 0;
alertInfoLabel.lineBreakMode = NSLineBreakByWordWrapping;
alertInfoLabel.font = [UIFont systemFontOfSize:self.startTherapyButton.titleLabel.font.pointSize-2];
alertInfoLabel.text = NSLocalizedString(@"SynchronizingNew", nil);
ExpectedSize = [alertInfoLabel.text sizeWithFont:alertInfoLabel.font constrainedToSize:alertInfoLabel.frame.size lineBreakMode:NSLineBreakByWordWrapping];
alertInfoLabel.frame = CGRectMake(alertInfoLabel.frame.origin.x,
self.startTherapyButton.frame.origin.y - ExpectedSize.height - IPAD*2,
alertInfoLabel.frame.size.width,
ExpectedSize.height);
[self addSubview:alertInfoLabel];
[self.containerButton addSubview:self];
return self;
//show the synchronization result message
- (void)setMessageLabelString:(NSString *)labelName
self.messageLabel.text = labelName;
ExpectedSize = [labelName sizeWithFont:self.messageLabel.font constrainedToSize:CGSizeMake(self.messageLabel.frame.size.width, VIEW_HEIGHT) lineBreakMode:NSLineBreakByWordWrapping];
self.messageLabel.frame = CGRectMake(self.messageLabel.frame.origin.x,
self.messageLabel.frame.origin.y,
self.messageLabel.frame.size.width,
ExpectedSize.height);
timer = [NSTimer scheduledTimerWithTimeInterval:0.8 target:self selector:@selector(MessageLabelBlinking) userInfo:nil repeats:YES];
// self.messageLabel.adjustsFontSizeToFitWidth = YES;
- (void)MessageLabelBlinking
if (_blinking)
NSString *threeDot = @".....";
if ([self.messageLabel.text rangeOfString:threeDot].location == NSNotFound)
self.messageLabel.text = [self.messageLabel.text stringByAppendingString:@"."];
else
self.messageLabel.text = [self.messageLabel.text stringByReplacingOccurrencesOfString:threeDot withString:@""];
else
[timer invalidate];
timer = nil;
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
// Drawing code
*/
//init the data processing block
- (void)initCustomOtherParameters
self.dataManager.DelegateCustom = self;
self.dataManager.blockProcessingData = ^(float allCommand, float restCommand)
if (allCommand == 0)
[[SingletonOperationQueue mainQueue] addOperationWithBlock:^
self.demoProgressView.progressView.progress = 1;
NSString *messageStr = [NSLocalizedString(@"SuccessfulSynchronized", nil) stringByAppendingFormat:@"\n%@", NSLocalizedString(@"EmptyTherapy", nil)];
[self setMessageLabelString:messageStr];
_blinking = NO;
self.CancelButton.alpha = 1.0;
];
else
float percenAger = (restCommand/allCommand);
percenAger = 1 - percenAger;
[[SingletonOperationQueue mainQueue] addOperationWithBlock:^
self.demoProgressView.progressView.progress = percenAger;
if (restCommand == 0)
[self downloadZipFile];
];
;
[Patient RemovePatient];
[self.singlePatient SavePatient];
- (void)showInView:(UIView *)view
self.transform = CGAffineTransformScale(self.transform, 0.8, 0.8);
self.containerButton.alpha = 0.0f;
self.containerButton.frame = view.bounds;
[view addSubview:self.containerButton];
[UIView animateWithDuration:0.15 animations:^
self.containerButton.alpha = 1.0f;
self.transform = CGAffineTransformScale(self.transform, 1.4, 1.4);
completion:^(BOOL finished)
if (finished)
[UIView animateWithDuration:0.20 animations:^
self.transform = CGAffineTransformIdentity;
];
[self sendConnectionTestRequest];
else
self.transform = CGAffineTransformIdentity;
[self sendConnectionTestRequest];
];
- (void)dismissMenuPopover
[self hide];
- (void)hide
[UIView animateWithDuration:0.25 animations:^
self.transform = CGAffineTransformScale(self.transform, 0.8, 0.8);
self.containerButton.alpha = 0.0f;
completion:^(BOOL finished)
if (finished)
[self.containerButton removeFromSuperview];
];
- (void)pressCancelButton:(UIButton *)button
[self.dataManager CommunicationCancel];
[self.delegateCustom SynchroningViewCancelButtonDidClicked:self];
- (void)startTherapyButtonDidClicked:(UIButton *)button
[self.delegateCustom SynchroningViewStartTherapyButtonDidClicked:self];
- (void)pressConfirmButton:(UIButton *)button
[UIView animateWithDuration:0.25 animations:^
self.CancelButton.alpha = 0.0;
self.ConfirmButton.alpha = 0.0;
];
[self sendRegistrationRequestConfirm:YES];
#pragma mark - Communication
- (void)sendConnectionTestRequest
[self initCustomOtherParameters];
_blinking = YES;
[self setMessageLabelString:NSLocalizedString(@"StartRegistration", nil)];
[self.dataManager sendRequestCommand:kConnectionTest];
- (void)sendRegistrationRequestConfirm:(BOOL)Confirm
[self setMessageLabelString:NSLocalizedString(@"StartRegistration", nil)];
NSString *registrationResult = [self.dataManager RegisterTheUSER_Confirm:Confirm];
[self processLogInResult:registrationResult];
- (void)processLogInResult:(NSString *)logInResult
if ([logInResult isEqual:@"1"])
if ([self.dataManager DataInitialization])
[self.dataManager DataInitializationForFakeUser];
[self.singlePatient SavePatient];
[self startTherapyButtonDidClicked:nil];
else if ([logInResult isEqual:@"2"])
if ([self.dataManager DataInitialization])
self.singlePatient.record7_AuthenticatedUser = YES;
[self.singlePatient SavePatient];
[self.dataManager sendRequestCommand:kNewDataAvailable];
;
else if ([logInResult intValue] == DEVICE_NOT_REGISTERED)
logInResult = NSLocalizedString(@"105", nil);
_blinking = NO;
[self setMessageLabelString:logInResult];
[UIView animateWithDuration:0.25 animations:^
self.CancelButton.alpha = 1.0;
self.ConfirmButton.alpha = 1.0;
];
else if ([logInResult isEqualToString:kNO])
_blinking = NO;
[self setMessageLabelString:@"Cannot find the Error "];
[UIView animateWithDuration:0.25 animations:^
self.CancelButton.alpha = 1.0;
];
else
_blinking = NO;
[self setMessageLabelString:logInResult];
[UIView animateWithDuration:0.25 animations:^
self.CancelButton.alpha = 1.0;
];
- (void)downloadZipFile
self.demoProgressView.progressView.progress = 1.0;
sleep(0.4);
[self setMessageLabelString:NSLocalizedString(@"Loading Data", nil)];
self.demoProgressView.progressView.progress = 0.0;
self.dataManager.blockProcessingDataPercentAge = ^(float percentAge, NSString *fileName)
if ([fileName isEqualToString:kaderenzainfo])
[[SingletonOperationQueue mainQueue] addOperationWithBlock:^
self.demoProgressView.progressView.progress = percentAge;
NSLog(@"%f", percentAge);
if (percentAge == 0.5)
sleep(0.4);
NSString *aderenzainfoFilePath = [[NSUserDefaults standardUserDefaults] objectForKey:kaccertamentiinfo];
[self.dataManager downloadZipFile:aderenzainfoFilePath fileName:kaccertamentiinfo];
];
else if ([fileName isEqualToString:kaccertamentiinfo])
[[SingletonOperationQueue mainQueue] addOperationWithBlock:^
self.demoProgressView.progressView.progress = 0.5 + percentAge;
if (0.5 + percentAge >= 1.0)
_blinking = NO;
self.CancelButton.alpha = 1.0;
if ([Patient getPatient].record_patientStatus == PatientStatusSuspendedType)
[self setMessageLabelString:NSLocalizedString(@"SuspendedPatient", nil)];
else if ([Patient getPatient].record_patientStatus == PatientStatusDeletedType)
[self setMessageLabelString:NSLocalizedString(@"DeletedPatient", nil)];
else if ([Patient getPatient].record_patientStatus == PatientStatusActiveType)
[self setMessageLabelString:NSLocalizedString(@"SuccessfulSynchronized", nil)];
self.startTherapyButton.alpha = 1.0;
];
;
NSString *aderenzainfoFilePath = [[NSUserDefaults standardUserDefaults] objectForKey:kaderenzainfo];
[self.dataManager downloadZipFile:aderenzainfoFilePath fileName:kaderenzainfo];
#pragma mark - DataManagerDelegate
- (void)CommunicationConnectionTest:(BOOL)connected
if (connected)
[self sendRegistrationRequestConfirm:NO];
else
[self setMessageLabelString:NSLocalizedString(@"connectionTestFail", nil)];
[UIView animateWithDuration:0.25 animations:^
self.CancelButton.alpha = 1.0;
];
_blinking = NO;
- (void)CommunicationSendRequestCommandName:(NSString *)commandName
if ([commandName isEqualToString:kNewDataAvailable])
[self setMessageLabelString:NSLocalizedString(@"Synchronizing", nil)];
- (void)CommunicationReceiveResponseWithOKCommandName:(NSString *)commandName
- (void)CommunicationReceiveResponseWithRequestError:(NSString *)commandName
[self setMessageLabelString:NSLocalizedString(@"NetworkConnectionError", nil)];
_blinking = NO;
[UIView animateWithDuration:0.25 animations:^
self.CancelButton.alpha = 1.0;
];
- (void)CommunicationReceiveResponseCommandName:(NSString *)commandName WithErrorCode:(int)errorCode withErrorDescription:(NSString *)errorDescription
[self setMessageLabelString:NSLocalizedString(@"NewDataAvaiableErrorCode", nil)];
_blinking = NO;
[UIView animateWithDuration:0.25 animations:^
self.CancelButton.alpha = 1.0;
];
-(void)CommunicationZipFileFailDownload
[self setMessageLabelString:NSLocalizedString(@"ZipFileDownloadFail", nil)];
_blinking = NO;
[UIView animateWithDuration:0.25 animations:^
self.CancelButton.alpha = 1.0;
];
-(void)CommunicationZipFileIsNotReadAble
[self setMessageLabelString:NSLocalizedString(@"ZipFileUnzippedFail", nil)];
_blinking = NO;
[UIView animateWithDuration:0.25 animations:^
self.CancelButton.alpha = 1.0;
];
@end
【问题讨论】:
这通常表明您有内存泄漏或仍在使用的已释放对象。您是否尝试过使用泄漏仪器? 是的,我试过了。但是如果我尝试使用模拟器,我没有任何问题。如果我尝试使用设备,当应用程序崩溃时,仪器会停止并且它不会告诉我是哪一部分代码导致了问题。似乎仪器从构建运行项目,而不是从代码。 您是否使用诸如保护 malloc、scribble 等调试选项配置了您的调试方案? 是的,我编辑了方案。几天来我一直在研究这个内存问题。但我仍然没有找到任何解决方案。项目完成,这是最后一个问题。内存错误太难找了,如果我能找到导致问题的代码部分就好了。 能贴出相关代码吗? 【参考方案1】:我终于解决了
在我的加密和解密函数中,我有这个:
Byte *buffer = (Byte*)malloc(asciiDataLength);
用缓冲区处理后,我将其转换为 NSData:
NSData *plainData = [NSData dataWithBytesNoCopy:buffer length:asciiDataLength freeWhenDone:YES];
此代码导致我的应用程序不断崩溃,我将其更改为
NSData *plainData = [NSData dataWithBytes:buffer length:asciiDataLength];
free(buffer);
然后我的应用再也不会崩溃了。
所以,我必须自己释放字节,ARC不会为我释放它。
【讨论】:
ARC 适用于 objects,而不是“C”级函数,例如malloc
。 SO上有一些解决方案不使用malloc
,只使用NSMutableData
。【参考方案2】:
模拟器的内存 = PC 的 RAM,即 4 或 6 GB 等。
并且设备最大只有 1 GB。在Xcode中运行app时,需要点击Debug Navigator
,然后点击Memory,会显示app的内存消耗情况。
要查看代码中的内存泄漏 - 您必须使用内存工具,例如 Instruments。
【讨论】:
以上是关于iOS - 如果仅在设备上运行,我的应用程序会因内存错误而崩溃的主要内容,如果未能解决你的问题,请参考以下文章
Flutter 无法仅在物理 iOs 设备中构建和运行 iOS 应用程序