我真的很挣扎于这个基本的iOS编程,但我无法弄清楚发生了什么以及如何解决它。
我有一个主要的Login控制器,用于检测用户何时登录并在auth成功时显示下一个控制器:
@interface LoginViewController (){
//Main root instance
RootViewController *mainPlatformRootControler;
}
-(void)loggedInActionWithToken:(NSString *)token anonymous:(BOOL)isAnon{
NSLog(@"User loged in.");
mainPlatformRootControler = [self.storyboard instantiateViewControllerWithIdentifier:@"rootViewCOntrollerStoryIdentifier"];
[self presentViewController:mainPlatformRootControler animated:YES completion:^{
}];
}
这很有效,没问题。
我的麻烦是处理退出。如何完全删除RootViewController实例并显示一个新实例?
我可以看到RootViewController实例正在堆叠,因为我有多个观察者,在注销后然后登录它们被多次调用(多次我退出并重新输入)。
我尝试过以下方法但没有成功:
首先检测RootViewController中的注销并解除:
[self dismissViewControllerAnimated:YES completion:^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"shouldLogOut" object:nil];
}];
然后在LoginViewController中:
-(void)shouldLogOut:(NSNotification *) not{
NSLog(@"No user signed in");
mainPlatformRootControler = NULL;
mainPlatformRootControler = nil;
}
那我怎么办呢?我知道它是一个基本的记忆处理东西,但我不知道怎么做?
答案 0 :(得分:1)
首先,你必须观察" shouldLogOut"在viewDidLoad中应如下所示:
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(shouldLogout:) name:@"shouldLogout" object:nil];
之后在dismissViewControllerAnimated中应如下所示:
[self dismissViewControllerAnimated:true completion:^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"shouldLogOut" object:nil];
}];
您需要在登录视图控制器中定义shouldLogOut:selector
-(void)shouldLogOut:(NSNotification *) not{
mainPlatformRootControler = nil;
}
希望这会对你有帮助!
答案 1 :(得分:0)
问题可能是您在注销发生时永远不会解雇RootViewController
。通过将属性mainPlatformRootControler
设置为nil
,您只需从LoginViewController
的角度放弃对象的所有权。这并没有说明任何其他也拥有对mainPlatformRootControler
背后的对象的引用。
要解决此问题,请在RootViewController
内为退出通知添加通知观察者,并在收到通知后,通过dismiss(animated:completion)
奖金如果你所做的只是保存它,你也不需要属性mainPlatformRootControler
。通过适当地解除它(以我上面写的方式),它将自动被清理,因此也不必担心nil
它。 (现在,如果你有其他理由保持mainPlatformRootControler
,那么不要删除它。
答案 2 :(得分:0)
因为登录和注销是一次性过程,所以登录后,不要只提供新的控制器,而只需用主控制器替换登录控制器。
让我们理解这一点: 您有主窗口的应用程序委托。
didFinishLaunch中的代码:
if (loggedIn) {
self.window = yourMainController
} else {
self.window = loginController
}
LoginController中的代码: LoginController将具有AppDelegate的实例,并且在登录后,您必须更改
appDelegate.window = mainController
MainController中的代码: MainController将具有AppDelegate的实例,并且在注销后,您必须更改
appDelegate.window = loginController
我希望这会有所帮助!!
答案 3 :(得分:0)
您是否在viewDidLoad
的{{1}}中添加了通知观察者,如下所示
LoginViewController
我猜你错过了这个,然后你的登录课在[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shouldLogOut:) name:@"shouldLogOut" object:nil];
被解雇后无法收到通知。
答案 4 :(得分:0)
正如你所说,有多个观察者创造了问题,那么当你不需要时,你必须要删除你的观察者。
在RootViewController中
public FileResult DownloadExcel(string filepath)
{
byte[] fileBytes = System.IO.File.ReadAllBytes(filepath);
return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet,
`enter code here`Path.GetFileName(filepath));
}
------------------------------------------------------------------------
因此,通过这种方式,您不必考虑您的RootViewController是否在堆栈中,或者是从新鲜等处加载。因为实际问题在于您的观察者。
答案 5 :(得分:0)
有许多正确的方法来管理视图层次结构,但我会分享一种我认为简单而有效的方法。
基本上,我在退出/进入时换出主UIWindow
的{{1}}。此外,我以编程方式提供rootViewController
而不是让rootViewController
加载初始视图控制器。这样做的好处是,在应用程序启动期间,如果用户已登录,则永远不必加载@UIApplicationMain
。
可以配置Login.storyboard
功能以适应您的风格,但我喜欢交叉溶解过渡,因为它们非常简单。
show
此代码是一个完整的示例,您可以创建一个新项目,清除“主界面”字段,然后将此代码放入应用程序委托中。
结果转换:
答案 6 :(得分:0)
由于您正在解除RootViewController并且在注销后没有引用但是实例未发布,唯一的另一种可能性是其他东西保留对RootViewController的引用。您可能有一个保留周期。 如果两个对象彼此具有强引用,则会发生保留循环。并且因为在释放所有强引用之前无法取消分配对象,所以内存泄漏。
保留周期的例子包括:
>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
>>> r.status_code
200
>>> r.headers['content-type']
'application/json; charset=utf8'
>>> r.encoding
'utf-8'
>>> r.text
u'{"type":"User"...'
>>> r.json()
{u'private_gists': 419, u'total_private_repos': 77, ...}
或者
RootViewController *root = [[RootViewController alloc] init];
AnOtherViewController *another = [[AnOtherViewController alloc] init];
//The two instances reference each other
root.anotherInstance = another;
another.rootInstance = root;
解决方案是为其中一个引用使用弱指针。因为弱指针是不保留其目标的指针。 e.g。
self.block = ^{
//self is captured strongly by the block
//and the block is captured strongly by the self instance
NSLog(@"%@", self);
};
和
@property(weak) RootViewController *anotherInstance;