- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
此处的代码是从RootViewController启动的模式视图,用于在影片下方显示带有缩略图胶片的视频,然后将定时指令绑定到该影片。
一切正常,但是内存泄漏/缺少发行版让我看不到,花了三天时间对其进行修复,现在是时候寻求帮助了...
如果我通过注释掉它来禁用NSNotificationCenter(在.m中突出显示),那么我对内存没有任何问题,并且保留了定时文本。但是我也没有任何缩略图。我尝试在许多地方插入[[NSNotificationCenter alloc] removeObserver:self];
来查看是否可以摆脱它。但是a,无济于事。
我也尝试过发布“ backgroundTimer”,但是当我尝试编译和运行时并没有给我留下深刻的印象。
本质上,第一次加载模式视图时,没有任何问题,而且看起来都很好-但是,如果用-(IBAction)close:(id)sender;
关闭它,则下次下次启动同一页面时似乎没有释放任何东西。每次重新启动模式视图时,内存使用量都会增加约30%(大约是缩略图生成所使用的量),并且增加的量大致相同。
请记住,我是新手,这个错误很可能会使您知道的人变得愚蠢。但是为了完成这个项目,我很乐意接受您喜欢对我的任何虐待。
这是代码:
。H
#import <UIKit/UIKit.h>
#import <MediaPlayer/MPMoviePlayerController.h>
#import "ImageViewWithTime.h"
#import "CommentView.h"
@interface SirloinVideoViewController_iPad : UIViewController {
UIView *landscapeView;
UIView *viewForMovie;
MPMoviePlayerController *player;
UILabel *onScreenDisplayLabel;
UIScrollView *myScrollView;
NSMutableArray *keyframeTimes;
NSArray *shoutOutTexts;
NSArray *shoutOutTimes;
NSTimer *backgroundTimer;
UIView *instructions;
}
-(IBAction)close:(id)sender;
-(IBAction)textInstructions:(id)sender;
@property (nonatomic, retain) IBOutlet UIView *instructions;
@property (nonatomic, retain) NSTimer *theTimer;
@property (nonatomic, retain) NSTimer *backgroundTimer;
@property (nonatomic, retain) IBOutlet UIView *viewForMovie;
@property (nonatomic, retain) MPMoviePlayerController *player;
@property (nonatomic, retain) IBOutlet UILabel *onScreenDisplayLabel;
@property (nonatomic, retain) IBOutlet UIScrollView *myScrollView;
@property (nonatomic, retain) NSMutableArray *keyframeTimes;
-(NSURL *)movieURL;
- (void) playerThumbnailImageRequestDidFinish:(NSNotification*)notification;
- (ImageViewWithTime *)makeThumbnailImageViewFromImage:(UIImage *)image andTimeCode:(NSNumber *)timecode;
- (void)handleTapFrom:(UITapGestureRecognizer *)recognizer;
@end
#import "SirloinVideoViewController_iPad.h"
#import "SirloinTextViewController.h"
@implementation SirloinVideoViewController_iPad
@synthesize theTimer, backgroundTimer, viewForMovie, player,
onScreenDisplayLabel, myScrollView, keyframeTimes, instructions;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
[nibNameOrNil release];
[nibBundleOrNil release];
}
- (IBAction)close:(id)sender{
[self.parentViewController dismissModalViewControllerAnimated:YES];
[player stop];
[player release];
[theTimer invalidate];
[theTimer release];
[backgroundTimer invalidate];
[SirloinVideoViewController_iPad release];
}
-(IBAction)textInstructions:(id)sender {
SirloinTextViewController *vController = [[SirloinTextViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:vController animated:YES];
[vController release];
}
- (void)viewDidLoad {
[super viewDidLoad];
keyframeTimes = [[NSMutableArray alloc] init];
shoutOutTexts = [[NSArray
arrayWithObjects:
@"1. XXXXXXXXXXXX",
@"2. XXXXXXXXXXXX",
@"3. XXXXXXXXXXXX",
@"4. XXXXXXXXXXXX",
@"5. XXXXXXXXXXXX",
@"6. XXXXXXXXXXXX"
@"7. XXXXXXXXXXXX",
@"8. XXXXXXXXXXXX",
@"9. XXXXXXXXXXXX",
@"10. XXXXXXXXXXXX",
@"11. XXXXXXXXXXXX",
@"12. XXXXXXXXXXXX",
@"13. XXXXXXXXXXXX",
@"14. XXXXXXXXXXXX",
@"15. XXXXXXXXXXXX",
nil] retain];
shoutOutTimes = [[NSArray
arrayWithObjects:
[[NSNumber alloc] initWithInt: 1],
[[NSNumber alloc] initWithInt: 73],
[[NSNumber alloc] initWithInt: 109],
[[NSNumber alloc] initWithInt: 131],
[[NSNumber alloc] initWithInt: 205],
[[NSNumber alloc] initWithInt: 250],
[[NSNumber alloc] initWithInt: 337],
[[NSNumber alloc] initWithInt: 378],
[[NSNumber alloc] initWithInt: 402],
[[NSNumber alloc] initWithInt: 420],
[[NSNumber alloc] initWithInt: 448],
[[NSNumber alloc] initWithInt: 507],
[[NSNumber alloc] initWithInt: 531],
[[NSNumber alloc] initWithInt: 574],
nil] retain];
self.player = [[MPMoviePlayerController alloc] init];
self.player.contentURL = [self movieURL];
self.player.view.frame = self.viewForMovie.bounds;
self.player.view.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[self.viewForMovie addSubview:player.view];
backgroundTimer = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
[self.view addSubview:self.myScrollView];
//I am pretty sure that this is the culprit - Just not sure why...
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(movieDurationAvailable:)
name:MPMovieDurationAvailableNotification
object:theTimer];
//Could be wrong, but when commented out I don't have the memory issues
}
- (NSInteger)positionFromPlaybackTime:(NSTimeInterval)playbackTime
{
NSInteger position = 0;
for (NSNumber *startsAt in shoutOutTimes)
{
if (playbackTime > [startsAt floatValue])
{
++position;
}
}
return position;
}
-(NSURL *)movieURL
{
NSBundle *bundle = [NSBundle mainBundle];
NSString *moviePath =
[bundle
pathForResource:@"sirloin"
ofType:@"m4v"];
if (moviePath) {
return [NSURL fileURLWithPath:moviePath];
} else {
return nil;
}
}
NSTimeInterval lastCheckAt = 0.0;
- (void)timerAction: theTimer
{
int count = [shoutOutTimes count];
NSInteger position = [self positionFromPlaybackTime:self.player.currentPlaybackTime];
NSLog(@"position is at %d", position);
if (position > 0)
{
--position;
}
if (position < count)
{
NSNumber *timeObj = [shoutOutTimes objectAtIndex:position];
int time = [timeObj intValue];
NSLog(@"shout scheduled for %d", time);
NSLog(@"last check was at %g", lastCheckAt);
NSLog(@"current playback time is %g", self.player.currentPlaybackTime);
if (lastCheckAt < time && self.player.currentPlaybackTime >= time)
{
NSString *shoutString = [shoutOutTexts objectAtIndex:position];
NSLog(@"shouting: %@", shoutString);
CommentView *cview = [[CommentView alloc] initWithText:shoutString];
[self.instructions addSubview:cview];
[shoutString release];
}
}
lastCheckAt = self.player.currentPlaybackTime;
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
-(void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath {
[[NSNotificationCenter defaultCenter] removeObserver:MPMovieDurationAvailableNotification];
[[NSNotificationCenter defaultCenter] removeObserver:MPMoviePlayerThumbnailImageRequestDidFinishNotification];
[keyPath release];
}
- (void) movieDurationAvailable:(NSNotification*)notification {
float duration = [self.player duration];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(playerThumbnailImageRequestDidFinish:)
name:MPMoviePlayerThumbnailImageRequestDidFinishNotification
object:nil];
NSMutableArray *times = [[NSMutableArray alloc] init];
for(int i = 0; i < 20; i++) {
float playbackTime = i * duration/20;
[times addObject:[NSNumber numberWithInt:playbackTime]];
}
[self.player
requestThumbnailImagesAtTimes:times
timeOption: MPMovieTimeOptionExact];
}
- (void) playerThumbnailImageRequestDidFinish:(NSNotification*)notification {
NSDictionary *userInfo = [notification userInfo];
NSNumber *timecode =
[userInfo objectForKey: MPMoviePlayerThumbnailTimeKey];
UIImage *image =
[userInfo objectForKey: MPMoviePlayerThumbnailImageKey];
ImageViewWithTime *imageView =
[self makeThumbnailImageViewFromImage:image andTimeCode:timecode];
[myScrollView addSubview:imageView];
UITapGestureRecognizer *tapRecognizer =
[[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(handleTapFrom:)];
[tapRecognizer setNumberOfTapsRequired:1];
[imageView addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
[image release];
[imageView release];
}
- (void)handleTapFrom:(UITapGestureRecognizer *)recognizer {
ImageViewWithTime *imageView = (ImageViewWithTime *) recognizer.view;
self.player.currentPlaybackTime = [imageView.time floatValue];
}
- (ImageViewWithTime *)makeThumbnailImageViewFromImage:(UIImage *)image andTimeCode:(NSNumber *)timecode {
float timeslice = self.player.duration / 3.0;
int pos = [timecode intValue] / (int)timeslice;
float width = 75 *
((float)image.size.width / (float)image.size.height);
self.myScrollView.contentSize =
CGSizeMake((width + 2) * 13, 75);
ImageViewWithTime *imageView =
[[ImageViewWithTime alloc] initWithImage:image];
[imageView setUserInteractionEnabled:YES];
[imageView setFrame:CGRectMake(pos * width + 2, 0, width, 75.0f)];
imageView.time = [[NSNumber alloc] initWithFloat:(pos * timeslice)];
return imageView;
[myScrollView release];
}
- (void)dealloc {
[player release];
[viewForMovie release];
[onScreenDisplayLabel release];
[keyframeTimes release];
[instructions release];
[shoutOutTexts release];
[shoutOutTimes release];
[super dealloc];
}
@end
最佳答案
您的问题确实多于一个泄漏。
第一个
在您的initWithNibName:bundle:
中,因为您在那里没有做任何有用的事情:完全摆脱它! (此外:不要释放传递给您的方法的参数!幸运的是,您已将这些释放放置在无法访问的行中,即,在return语句之后...)
下一个方法,下一个问题
为什么将release
发送到类对象?别!在许多层面上都是错误的。
您已决定为计时器创建属性。本身没有什么不好。但是,为什么要在这里直接使用ivars?我强烈建议您实现setTheTimer:
和setBackgroundTimer:
来处理失效并正确释放,只需在此处执行self.theTimer = nil; self.backgroundTimer = nil;
即可。这也将解决不对称性。 (顺便说一句:对于ivar,theTimer并不是一个好名字……尤其是当另一个ivar是一个计时器时!)textInstructions:
看起来并不令人怀疑,但是...viewDidLoad
还有其他问题
它泄漏了MPMoviePlayerController:@property
将保留它,因此您需要在此处平衡alloc
。backgroundTimer
有一个相应的@property
声明为保留:您在这里违反了此API约定,因为您仅将计时器分配给了ivar。请改用self.backgroundTimer = ...
。
从您发布的所有代码中,在我看来,将theTimer
作为对-[NSNotificationCenter addObserver:selector:name:object:]
的调用中的最后一个参数传递是将nil
作为该参数传递的一种不错的方式。这很好,因为通常NSTimer
不会发布太多的MPMovieDurationAvailableNotification
。实际上,除了在theTimer
中我看不到使用close:
之外:难道这只是您引入backgroundTimer
ivar / @ property之前的无用残留? (还有另一个同名变量,但是应该伴随着一个大的胖编译器警告...)
您是否以任何方式实现viewDidUnload
?如果是这样,请执行以下操作:self.player = nil;
?[shoutOutTexts release], shoutOutTexts = nil;
?[shoutOutTimes release], shoutOutTimes = nil;
?self.keyframeTimes = nil;
?[[NSNotificationCenter defaultCenter] removeObserver:self name: MPMovieDurationAvailableNotification object:nil];
?self.backgroundTimer = nil;
? (假定setBackgroundTimer:
释放旧值并使之无效)
更新我第一次错过了这个:您在这里泄漏了15个NSNumber
。在[NSNumber numberWithInt:]
的设置中使用shoutOutTimes
代替alloc / init。
关于movieURL
的小注释,您可以将其转换为以下单线:
-(NSURL*)movieURL {
return [[NSBundle mainBundle] URLForResource:@"sirloin" withExtension:@"m4v"];
}
NSTimeInterval lastCheckAt = 0.0;
在全球范围内。从您的用法来看:ivar PLZ?!?一个?
timerAction:
-[NSArray count]
返回
NSUInteger
,并且U不是错字,而是表示该值是无符号的。您当然不会在此应用程序中遇到签名问题,并且很少在其他情况下遇到这种情况,但是当您这样做时,它们会弥补真正的时髦错误,因此您应该意识到其中的含义...
CommentView
,而同时—过度释放了一个
NSString
。实际上,您首先使用的是字符串文字(永远不会取消分配),(即在初始化shoutOutTimes时)完全可以节省您的屁股。
removeObserver:forKeyPath:
removeObserver:forKeyPath:
是
NSKeyValueObserving
非正式协议中的一种方法,与您在其中使用(滥用)该协议所完成的工作完全不同。
super
。 (嗯,除了,当您也重写
addObserver:forKeyPath:options:context:
时,它应该不说您不应该做那件事,除非您真的知道自己在做什么-如果您曾计划使用KVO。)
movieDurationAvailable:
times
。寻求他的建议,或者改为-
NSMutableArray *times = [NSMutableArray array];
,您就完成了。
playerThumbnailImageRequestDidFinish:
image
,所以不要释放它!
makeThumbnailImageViewFromImage:andTimeCode:
NSNumber
(使用
[NSNumber numberWithFloat:(pos * timeslice)]
而不是
alloc/initWithFloat:
-dance),并防止了由于紧随其后的无条件return语句(phe!)而过度释放
myScrollView
而导致崩溃。
newThumbnailImageView...
,以便在一年左右的时间重新访问此代码时,您立即知道
[imageView release];
底部的
playerThumbnailImageRequestDidFinish:
确实是必要的,而无需看一下这个方法的实现。
thumbnailImageView...
并将return语句更改为
return [imageView autorelease];
。奖励:随着
playerThumbnailImageRequestDidFinish:
的过时,
[imageView release];
中的一行减少了。
dealloc
[[NSNotificationCenter defaultCenter] removeObserver:self];
。
landscapeView
。)
关于ios - Xcode-iOS内存泄漏使我发疯,我认为是NSNotificationCenter,但希望新鲜的眼睛能看到我看不到的东西,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5843665/
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
class Person def name puts "Doharey" end end puts Person.class #=> this out puts Class puts
在 PHP 中,($myvariable==0)当 $myvariable 为零时,表达式的值为真;当 $myvariable 为 null 时,此表达式的值也为 true。如何排除第二种情况?我的意
正文 Oracle的一顿猛如虎操作,让开发者彻底失去了Java EE。Eclipse基金会则自立门户,另起炉灶开启Jakarta EE项目。 对于Jakarta EE,从它
我是 python 新手,建议我使用 Canopy。我正在努力跟进 with this tutorial ,但我陷入了 mahotas.imread 行。我收到一个错误,说以这个结尾: Full er
上下文是我们想要跟踪应用程序的用户行为,因为它具有不同的功能。 为此,我们创建了一个自定义 Angular Directive(指令),例如myFunctionality并将 HTML 部分包装到此指
我正在尝试在文本字段中实现 google Places api 的自动完成功能。这是我的代码: $(document).ready(function() { initialize(){ v
我在 Glassfish 3.1.1 中配置了一个新的 jdbcRealm 并打开了 FINEST 日志记录,当我尝试使用用户名和密码登录时,我得到以下信息。它提示我的 Web 应用程序映射到的领域是
问题是,即使我将线程设置为“thrd.IsBackground = false”,iis 也不认为它正在运行,即使这是一个长时间运行的进程。如果我不关闭应用程序池的空闲关闭,它将关闭,因为它认为它是空
我正在使用 OpenJDK 8(从 https://jdk.java.net/java-se-ri/8 下载并解压,添加到 PATH),并且遇到了证书错误。 经过调查,我意识到 cacerts 存在问
我基于 Firebase 制作了简单的后期制作项目。我将帖子保存到 Firebase 中,如下所示: let data = UIImageJPEGRepresentation(newPostImage
我觉得还是先说明情况比较好。 情况 我正在编写一些软件来过滤 Set 的 File。 过滤器如下:如果文件未隐藏,则将其添加到新的 Set。 问题在于 File.isHidden() 的当前行为如下:
我创建了一个 C++ DLL 函数,它使用多个数组来处理最终的图像数据。我正在尝试通过引用传递这些数组,进行计算,然后通过预分配数组中的引用将输出传回。在该函数中,我使用了 Intel Perform
我在 python 中有一个小应用程序,除了这个小问题之外,它工作得很好:它应该连续运行一个循环,直到用户通过按钮告诉它停止,但是当我点击开始按钮时,Windows 告诉我它不是回应。现在,如果我编写
代码运行正常,但我怎么会得到这个错误日志 错误日志: 08-28 08:44:24.281: E/MediaPlayer(32454): mOnVideoSizeChangedListener is
我有一个使用 Karma+Jasmine 和 JSHint 的 Grunt 设置。每当我在我的规范文件上运行 JSHint 时,我都会收到一系列“未定义”错误,其中大部分是针对 Jasmine 的内置
将以下代码保存到文件中,Ubuntu 14.04 正确地意识到它是 bash: #!/usr/bin/env bash awk '{print $1 $2}' my_file 然而,向 awk 添加关
以下代码返回 false import inspect print(inspect.isbuiltin(map)) 但是 map 功能在"built-in" functions下列出. 为什么会这样?
这是一段常见的示例代码: while (1) { print "foo\n"; } 永远打印“foo”。 perl foo.pl foo foo foo ... 和 while (0) { p
我对 Haskell 比较陌生,来自 F#(一种 Microsoft 语言)。 我已经从脚手架创建了一个 Yesod 项目,稍微玩了一下,调整了一些东西,但随后它停止工作,并显示此错误消息(在所有模块
我是一名优秀的程序员,十分优秀!