ios - DetailViewController 中的保留周期 - 启用 ARC

标签 ios iphone objective-c memory-management

我在呈现/关闭我的 DetailViewController 时得到一个保留周期。非常感谢任何帮助在下面的代码中找到保留周期的机会。

问题:下面贴出的代码中有没有retain cycle?

enter image description here

苹果:6

代码:4.6

测试:iphone 4 设备

ARC 启用

编辑: 添加了仪器照片。

DetailViewController.h

@interface SRDetailViewController : UIViewController 

@property (weak, nonatomic) IBOutlet UILabel *roomTitle;
@property (weak, nonatomic) IBOutlet UIView *userScreenContainer;
@property (weak, nonatomic) IBOutlet UIView *opponentScreenContainer;
@property (weak, nonatomic) IBOutlet UILabel *statusLabel;
@property (weak, nonatomic) IBOutlet UIButton *retryButton; 
@property (weak, nonatomic) IBOutlet UIProgressView *progressBar;
@property (strong, nonatomic) NSTimer *progressTimer;
@property (strong, nonatomic) NSTimer *retryTimer;
@property (weak, nonatomic) IBOutlet UIView *bottomViewContainer;


@property (strong, nonatomic) SRRoom *room;

@property (strong, nonatomic) SROpenTokVideoHandler *openTokHandler;

DetailViewController.m

@interface SRDetailViewController ()

@property (strong, nonatomic) NSString* kApiKey;
@property (strong, nonatomic) NSString* kSessionId;
@property (strong, nonatomic) NSString* kToken;


@end

@implementation SRDetailViewController


- (void)viewDidLoad
{
    [super viewDidLoad];
    [self configOpentTok];
    [self performGetRoomRequest];
    [self configNavBar];
    [self configNotifcations];
    [self configProgressBar];

}

-(void)configSocialSharing
{
    //check if it already exists
    for(UIView *subview in self.view.subviews){
        if([subview isKindOfClass:[SRSocialSharing class]]){
            return;
        }
    }

    //add off screen
    CGRect frame = CGRectMake(0, [[UIScreen mainScreen] bounds].size.height, [[UIScreen mainScreen] bounds].size.width, 44);
    SRSocialSharing *share = [[SRSocialSharing alloc] initWithFrame:frame];
    [self.view addSubview:share];

    share.sharingURL = [self createUrlForSharing];
    //animate in
    frame = CGRectMake(0, [[UIScreen mainScreen] bounds].size.height-100, [[UIScreen mainScreen] bounds].size.width, 44);
    [UIView animateWithDuration:3 delay:2 options:UIViewAnimationOptionCurveEaseOut animations:^{
        share.frame = frame;
    } completion:nil];
}

-(NSURL *)createUrlForSharing
{
    NSRange range = NSMakeRange(self.room.sessionId.length-7, 6);
    NSString *shortSessionId = [self.room.sessionId substringWithRange:range];
    NSString *urlString = [NSString stringWithFormat:@"url/invites/%@/%@?sessionId=%@",self.room.topicId, [self opposingPosition:self.room.position],shortSessionId];
    return [NSURL URLWithString:urlString];
}
-(NSString *)opposingPosition:(NSString*)position
{
    return ([position isEqualToString:@"agree"])? @"disagree" : @"agree";
}


-(void) configOpentTok{   
    [self.openTokHandler registerUserVideoStreamContainer:self.userScreenContainer];
    self.openTokHandler.userVideoStreamConatinerName = self.room.position;

    [self.openTokHandler registerOpponentOneVideoStreamContainer:self.opponentScreenContainer];
    self.openTokHandler.opponentOneVideoStreamConatinerName = [self opposingPosition:self.room.position];

    self.openTokHandler.shouldPublish = YES;
    self.openTokHandler.isObserving = NO;
}

-(void)configNavBar
{

    UIImage *backButtonImage = [UIImage imageWithContentsOfFile:@"backButton"];
    UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [backButton setFrame:CGRectMake(0, 0, 47, 32)];
    [backButton setImage:backButtonImage forState:UIControlStateNormal];
    [backButton addTarget:self action:@selector(pressBackButton) forControlEvents:UIControlEventTouchUpInside];
    UIBarButtonItem *navBackButton = [[UIBarButtonItem alloc] initWithCustomView:backButton];

    [self.navigationItem setLeftBarButtonItem:navBackButton];

    self.title = [self.room.position stringByReplacingCharactersInRange:NSMakeRange(0,1)
                                                   withString:[[self.room.position  substringToIndex:1] capitalizedString]];
}

-(void)pressBackButton{
    self.navigationItem.leftBarButtonItem.enabled = NO;
    [self manageSafeClose];
    double delayInSeconds = 3;
    //[self updateStatusLabel:@"Disconnecting" withColor:[UIColor grayColor]];

    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        [self.navigationController popViewControllerAnimated:YES];
    });
}

-(void)configNotifcations
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(recieveNotifications:)
                                                 name:kSROpenTokVideoHandlerNotifcations
                                               object:nil
     ];
}

-(void)recieveNotifications:(NSNotification *)notification
{
    if ([[notification name] isEqualToString:kSROpenTokVideoHandlerNotifcations]){
        NSDictionary *userInfo = notification.userInfo;
        NSNumber *message = [userInfo objectForKey:@"message"];
        [self statusMessage: message];
    }
}

-(void)statusMessage:(NSNumber*)message{

        NSString *result = nil;

        switch([message intValue]) {
            case 0:
                result = @"Disconnected";
                break;
            case 1:
                result = @"Connecting...";
                [self startRetryTimer];
                break;
            case 2:
                result = @"Publishing Your Video...";
                break;
            case 3:
                result = @"Searching for Idiots...";
                break;
            case 4:
                result = @"Start!";
                [self startProgressBar];
                [self stopTimer:self.retryTimer];
                break;
            case 5:
                [self stopTimer:self.progressTimer];
                result = @"Stopped!";
                break;
            case 6:
                [self stopTimer:self.progressTimer];
                result = @"Disconnecting...";
                break;
            case 7:
                result = @"Opponent failed to join. Retrying...";
                [self performSelector:@selector(retry) withObject:nil afterDelay:4];
                break;
            default:
                result = @"Retry";
        }

    [self updateStatusLabel:result withColor:[self statusLabelColorPicker:message] animated:YES];
    NSLog(@"STATUS LABEL UPDATE: %@", message);

}

-(UIColor*)statusLabelColorPicker:(NSString *)Message{
    return [UIColor whiteColor];
}

-(void)performGetRoomRequest{
    __weak typeof(self) weakSelf = self;
    [[RKObjectManager sharedManager] getObject:weakSelf.room
                                          path:nil
                                    parameters:nil
        success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult){
            weakSelf.openTokHandler.kToken = weakSelf.room.token;
            weakSelf.openTokHandler.kSessionId = weakSelf.room.sessionId;
            weakSelf.roomTitle.text = weakSelf.room.title;
            weakSelf.navigationController.title = weakSelf.room.position;
            [weakSelf configSocialSharing];
            [weakSelf.openTokHandler doConnectToRoomWithSession];
        }failure:^(RKObjectRequestOperation *operation, NSError *error){

    }];
}

-(void)dealloc
{
    self.room = nil;
}

-(void)manageSafeClose{
    [self stopTimer:self.retryTimer];
    [self stopTimer:self.progressTimer];
    [self.openTokHandler safetlyCloseSession];
    [[RKObjectManager sharedManager].operationQueue cancelAllOperations];
    self.openTokHandler = nil;
    self.title = nil;
    self.navigationItem.leftBarButtonItem = nil;
    self.kApiKey = nil;
    self.kSessionId= nil;
    self.kToken= nil;

    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [self doCloseRoom];
}

-(void)doCloseRoom
{
    __weak typeof(self) weakSelf = self;
    [[RKObjectManager sharedManager] deleteObject:weakSelf.room
                                             path:nil
                                       parameters:nil
                                          success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult){
                                              //NSLog(@"Mapping result %@", mappingResult);
                                          }
                                          failure:nil
     ];
}

-(void)startRetryTimer
{
    NSLog(@"Timer Started");
    self.retryTimer  = [NSTimer scheduledTimerWithTimeInterval:(60*5)
                                                        target:self
                                                      selector:@selector(retry)
                                                      userInfo:nil
                                                       repeats:YES];
}

-(void)retry
{
    [self doCloseRoom];
    [self performSelector:@selector(performGetRoomRequest) withObject:nil afterDelay:4];
}

#pragma mark - label
- (void)updateStatusLabel:(NSString *) message withColor:(UIColor*) color animated:(bool) animated
{
    self.statusLabel.text = message;
    if (animated) {
        [self fadeOutFadeInAnimation:self.statusLabel andColor:color];
    } else{
        [SRAnimationHelper stopAnimations:self.statusLabel];
    }

}

- (void)fadeOutFadeInAnimation:(UILabel *)label andColor:(UIColor*)color
{

    //add animation
    [label.layer addAnimation:[SRAnimationHelper fadeOfRoomStatusLabel] forKey:nil];

    //change label color
    label.textColor = color;
}




#pragma mark - Progress Bar
-(void)configProgressBar
{
    self.progressBar.progressTintColor = [UIColor orangeColor];
}

-(void)startProgressBar
{
    self.progressBar.hidden = NO;
    self.progressBar.progress = 0;
    self.progressTimer  = [NSTimer scheduledTimerWithTimeInterval:.5
                                                           target:self
                                                         selector:@selector(changeProgressValue)
                                                         userInfo:nil
                                                          repeats:YES];
}

-(void)stopTimer: (NSTimer*)timer
{
    [timer invalidate];
    timer = nil;
}

- (void)changeProgressValue
{

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        float progressValue         = self.progressBar.progress;
        progressValue               += .00834;
        if (progressValue > .99)
        {
            progressValue = 1;
            [self stopTimer:self.progressTimer];
            return;
        }

        NSString* time =[NSString stringWithFormat:@"%.0f", 60 - ceil(progressValue*60)];
        NSLog(@"Progress Value %f Time %@", progressValue, time);


        NSString *message = [NSString stringWithFormat:@"Time Left: %@",  time];

        dispatch_async(dispatch_get_main_queue(), ^(void) {
            self.progressBar.progress      = progressValue;
            [self updateStatusLabel:message withColor:[UIColor whiteColor] animated:NO];

        });
    });


}

@end

最佳答案

除了上面提到的计时器保留之外,所发布的代码中没有保留周期。我没有跟踪定时器的逻辑,但它很容易调试。

作为补充说明,这是我所见过的一些避免常见错误的最佳代码。您应该因出色的工作而受到赞扬。

关于ios - DetailViewController 中的保留周期 - 启用 ARC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19548668/

相关文章:

ios - 无法在 iOS 5 的其他类中执行 segue?

ios - 无法使用 textContainer 选择 UITextView

ios - 发送http删除请求

objective-c - Xcode Playground 并初始化 NSImage

iOS : using activity indicator in loading for second view controller

iphone - iPhone应用程序中的启动画面使用Storyboard延迟

ios - 用户退出模态视图时如何验证 uitextfields? (iOS)

ios - 有滑动菜单覆盖 View Controller ,而不是将它移到一边(iOS)

iphone - 关系的核心数据建模

iphone - 对 UITextField 的引用不起作用?