Objective C - 因保留周期而丢失
Objective C - Lost with retain cycles
关闭我的 VC 后,我注意到我并没有从内存中释放所有内容。我对如何找到我的保留周期感到非常迷茫。我使用的是 NSTimer 和 NSNotificationCenter,但我确保在退出前使 Observers 无效并移除,并且确保使用弱委托。
我的保留周期还会发生在其他什么地方?在动画块中?像这样?
[UIView animateWithDuration:.1 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.setListTableViewVertConst.constant = 0;
self.setListTableViewHeightConst.constant = 264;
} completion:^(BOOL finished) {
}];
使用 GCD 时,我确保使用 weakSelf。
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.remotePasswordTextField resignFirstResponder];
});
感谢您的帮助。
编辑:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//Send the room code to be displayed on the respective view controllers.
if ([segue.identifier isEqualToString:@"toSetListRoomVC"]) {
SetListRoomViewController *setListVC = segue.destinationViewController;
setListVC.roomCode = self.roomCodeTextField.text;
}
}
viewWIllApear
[super viewWillAppear:YES];
self.socket = [[SocketKeeperSingleton sharedInstance]socket];
self.socketID = [[SocketKeeperSingleton sharedInstance]socketID];
NSString *roomCodeAsHost = [[SocketKeeperSingleton sharedInstance]hostRoomCode];
/////////HOST/////////
if ([[SocketKeeperSingleton sharedInstance]isHost]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveHostSongAddedNotification:)
name:kQueueAdd
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveUserJoinedNotification:)
name:kUserJoined
object:nil];
NSLog(@"User is the host of this room");
self.isHost = YES;
[self viewForNoCurrentArtistAsHost];
self.roomCodeLabel.text = roomCodeAsHost;
if (!self.hostQueue) {
self.hostQueue = [[NSMutableArray alloc]init];
}
if (!self.hostCurrentArtist) {
self.hostCurrentArtist = [[NSMutableDictionary alloc]init];
}
if (!self.player) {
self.player = [[AVPlayer alloc]init];
}
if (!self.timer) {
self.timer = [[NSTimer alloc]init];
}
}
///////NOT HOST///////
else {
// Add a notifcation observer and postNotification name for updating the tracks.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveQueueUpdatedNotification:)
name:kQueueUpdated
object:nil];
//Add a notifcation observer and postNotification name for updating current artist.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveCurrentArtistUpdateNotification:)
name:kCurrentArtistUpdate
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveOnDisconnectNotification:)
name:kOnDisconnect
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveHostDisconnectNotification:)
name:kHostDisconnect
object:nil];
//Add some animations upon load up. Purple glow and tableview animation.
double delay = .4;
[self purpleGlowAnimationFromBottomWithDelay:&delay];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationBottom];
//Set Current artist, if there is one.
NSDictionary *currentArtist = [[SocketKeeperSingleton sharedInstance]currentArtist];
[self setCurrentArtistFromCurrentArtist:currentArtist];
//Set the current tracks, if there is one.
NSArray *setListTracks = [[SocketKeeperSingleton sharedInstance]setListTracks];
if (setListTracks) {
self.tracks = setListTracks;
}
}
}
表格视图
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView.tag == 1) {
if (self.isHost) {
return [self.hostQueue count];
}
else return [self.tracks count];
}
else return [self.searchTracks count];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
在此代码示例中,您没有将 __weak
用于 self
[UIView animateWithDuration:.1 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.setListTableViewVertConst.constant = 0;
self.setListTableViewHeightConst.constant = 264;
} completion:^(BOOL finished) {
}];
但是,乍一看,这似乎并没有创建保留循环。您发布的代码似乎没有,所以它可能在其他地方。你确定你有保留周期吗?
无论如何,请尝试 instrumenting 您的应用程序。可能会有帮助。
我注意到您在一些评论中使用了 "popOut" 这个词,所以我假设您使用的是导航控制器。
如果是这种情况,您的视图控制器将由其嵌入的导航控制器保留,不会被释放。导航控制器需要保存对您的 VC 的引用(参见 UINavigationController.viewControllers),以便当您在层次结构中弹出 top/next VC 时它可以返回到它。
这是预期的行为。
关闭我的 VC 后,我注意到我并没有从内存中释放所有内容。我对如何找到我的保留周期感到非常迷茫。我使用的是 NSTimer 和 NSNotificationCenter,但我确保在退出前使 Observers 无效并移除,并且确保使用弱委托。
我的保留周期还会发生在其他什么地方?在动画块中?像这样?
[UIView animateWithDuration:.1 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.setListTableViewVertConst.constant = 0;
self.setListTableViewHeightConst.constant = 264;
} completion:^(BOOL finished) {
}];
使用 GCD 时,我确保使用 weakSelf。
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.remotePasswordTextField resignFirstResponder];
});
感谢您的帮助。
编辑:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//Send the room code to be displayed on the respective view controllers.
if ([segue.identifier isEqualToString:@"toSetListRoomVC"]) {
SetListRoomViewController *setListVC = segue.destinationViewController;
setListVC.roomCode = self.roomCodeTextField.text;
}
}
viewWIllApear
[super viewWillAppear:YES];
self.socket = [[SocketKeeperSingleton sharedInstance]socket];
self.socketID = [[SocketKeeperSingleton sharedInstance]socketID];
NSString *roomCodeAsHost = [[SocketKeeperSingleton sharedInstance]hostRoomCode];
/////////HOST/////////
if ([[SocketKeeperSingleton sharedInstance]isHost]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveHostSongAddedNotification:)
name:kQueueAdd
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveUserJoinedNotification:)
name:kUserJoined
object:nil];
NSLog(@"User is the host of this room");
self.isHost = YES;
[self viewForNoCurrentArtistAsHost];
self.roomCodeLabel.text = roomCodeAsHost;
if (!self.hostQueue) {
self.hostQueue = [[NSMutableArray alloc]init];
}
if (!self.hostCurrentArtist) {
self.hostCurrentArtist = [[NSMutableDictionary alloc]init];
}
if (!self.player) {
self.player = [[AVPlayer alloc]init];
}
if (!self.timer) {
self.timer = [[NSTimer alloc]init];
}
}
///////NOT HOST///////
else {
// Add a notifcation observer and postNotification name for updating the tracks.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveQueueUpdatedNotification:)
name:kQueueUpdated
object:nil];
//Add a notifcation observer and postNotification name for updating current artist.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveCurrentArtistUpdateNotification:)
name:kCurrentArtistUpdate
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveOnDisconnectNotification:)
name:kOnDisconnect
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(receiveHostDisconnectNotification:)
name:kHostDisconnect
object:nil];
//Add some animations upon load up. Purple glow and tableview animation.
double delay = .4;
[self purpleGlowAnimationFromBottomWithDelay:&delay];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationBottom];
//Set Current artist, if there is one.
NSDictionary *currentArtist = [[SocketKeeperSingleton sharedInstance]currentArtist];
[self setCurrentArtistFromCurrentArtist:currentArtist];
//Set the current tracks, if there is one.
NSArray *setListTracks = [[SocketKeeperSingleton sharedInstance]setListTracks];
if (setListTracks) {
self.tracks = setListTracks;
}
}
}
表格视图
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView.tag == 1) {
if (self.isHost) {
return [self.hostQueue count];
}
else return [self.tracks count];
}
else return [self.searchTracks count];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
在此代码示例中,您没有将 __weak
用于 self
[UIView animateWithDuration:.1 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.setListTableViewVertConst.constant = 0;
self.setListTableViewHeightConst.constant = 264;
} completion:^(BOOL finished) {
}];
但是,乍一看,这似乎并没有创建保留循环。您发布的代码似乎没有,所以它可能在其他地方。你确定你有保留周期吗?
无论如何,请尝试 instrumenting 您的应用程序。可能会有帮助。
我注意到您在一些评论中使用了 "popOut" 这个词,所以我假设您使用的是导航控制器。
如果是这种情况,您的视图控制器将由其嵌入的导航控制器保留,不会被释放。导航控制器需要保存对您的 VC 的引用(参见 UINavigationController.viewControllers),以便当您在层次结构中弹出 top/next VC 时它可以返回到它。
这是预期的行为。