Ios 如何在ViewDid中执行一些只出现一次的操作?

Ios 如何在ViewDid中执行一些只出现一次的操作?,ios,viewdidappear,Ios,Viewdidappear,我想检查粘贴板,并在视图出现时显示一个警报,如果它包含特定值。我可以将代码放入viewDidLoad以确保只调用一次,但问题是警报视图显示得太快。我知道我可以设置一个计时器来延迟警报的出现,但我认为这不是一个好办法 我检查了这个问题,发现有一个步骤可以检查视图是否存在。所以我想知道是否有任何api可以实现这一点 更新:“仅一次”表示视图控制器实例的生存期您可以在ViewDidLoad方法中使用此函数 performSelector:withObject:afterDelay: 它将在延迟后调用该

我想检查粘贴板,并在视图出现时显示一个警报,如果它包含特定值。我可以将代码放入
viewDidLoad
以确保只调用一次,但问题是警报视图显示得太快。我知道我可以设置一个计时器来延迟警报的出现,但我认为这不是一个好办法

我检查了这个问题,发现有一个步骤可以检查视图是否存在。所以我想知道是否有任何api可以实现这一点


更新:“仅一次”表示视图控制器实例的生存期

您可以在ViewDidLoad方法中使用此函数

performSelector:withObject:afterDelay:

它将在延迟后调用该函数。因此,您不必使用任何自定义计时器对象。 这一次你可以用

dispatch_once DCD块。仅dispatch_once块中的performSelector在调用ViewDidLoad时将仅调用performSelector一次

希望有帮助

此解决方案在应用程序的整个生命周期内只调用一次
viewdide
,即使您创建了视图控制器的多个对象,一次之后也不会调用。请参阅 您可以在
viewdiload
中执行选择器,也可以在
viewdilease
中使用
dispatch\u once\t
。如果你找到更好的解决方案,请与我分享。我就是这样做的

- (void)viewDidLoad {
  [super viewDidLoad];
  [self performSelector:@selector(myMethod) withObject:nil afterDelay:2.0];
}

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  static dispatch_once_t once;
  dispatch_once(&once, ^{
    //your stuff
    [self myMethod];
  });
}

尝试设置布尔值,当情况发生时调用它

@interface AViewController : UIViewController
   @property(nonatomic) BOOL doSomeStuff;
@end

@implementation AViewController
- (void) viewWillAppear:(BOOL)animated
{
    if(doSomeStuff)
    {
       [self doSomeStuff];
       doSomeStuff = NO;
    }
}
在您初始化AViewController实例的某个地方:

AddEventViewController *ad = [AddEventViewController new];
ad.doSomeStuff = YES;
不确定为什么要在
视图中执行此操作?但如果您希望doSomeStuff是私有的,并且只调用了一次
soSomeStuff
,那么下面是另一个通知解决方案:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomeStuff) name:@"do_some_stuff" object:nil];

- (void) doSomeStuff
{}
然后在某处发布:

[[NSNotificationCenter defaultCenter] postNotificationName:@"do_some_stuff" object:nil];

如果我正确理解了您的问题,您可以简单地设置一个BOOL变量,以识别已调用viewDidAppear,例如:

- (void)viewDidAppear {
    if (!self.viewHasBeenSet) { // <-- BOOL default value equals NO

        // Perform whatever code you'd like to perform
        // the first time viewDidAppear is called

        self.viewHasBeenSet = YES; 
    }
}
-(无效)视图显示{

如果(!self.viewHasBeenSet){/有一个标准的内置方法可以用于此操作

目标C:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    if ([self isBeingPresented] || [self isMovingToParentViewController]) {
        // Perform an action that will only be done once
    }
}
Swift 3:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    if self.isBeingPresented || self.isMovingToParentViewController {
        // Perform an action that will only be done once
    }
}
当视图控制器作为modally显示的结果首次显示时,
isBeingPresented
的调用为真。
isMovingToParentViewController
在视图控制器首次被推到导航堆栈上时为真。当视图控制器第一次出现时,这两个调用之一为真

无需处理
BOOL
ivar或任何其他跟踪第一次呼叫的技巧。

通过阅读其他评论(并根据@rmaddy的回答),我知道这不是OP要求的,而是针对那些因为问题标题而来的人:

extension UIViewController {
    var isPresentingForFirstTime: Bool {
        return isBeingPresented() || isMovingToParentViewController()
    }
}
更新

您应该在
viewdideappear
viewWillAppear
中使用此方法(感谢@rmaddy)

更新2


此方法仅适用于模式显示的视图控制器和推式视图控制器。它不适用于childViewController。使用
didMoveToParentViewController
会更好地适用于childViewController。

rmaddy的答案非常好,但当视图控制器是根视图控制器时,它并不能解决问题导航控制器和所有其他容器的troller,这些容器不将这些标志传递给其子视图控制器

因此,在这种情况下,我发现最好使用一个标志,并在以后使用它

@interface SomeViewController()
{
    BOOL isfirstAppeareanceExecutionDone;
}
@end

@implementation SomeViewController

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if(isfirstAppeareanceExecutionDone == NO) {
        // Do your stuff
        isfirstAppeareanceExecutionDone = YES;
    }
}

@end

通过此检查,嵌套视图控制器中不应出现问题

extension UIViewController {

  var isPresentingForFirstTime: Bool {
      if let parent = parent {
        return parent.isPresentingForFirstTime
      }
      return isBeingPresented || isMovingFromParent
  }
}

我认为您不需要在
viewDidLoad
中将BOOL设置为NO。当创建对象时,BOOL将以
NO
开始,并且
viewDidLoad
,afaik,在视图控制器对象的生命周期中只调用一次。@MaxGabriel为了清晰起见,我这样写的,但是是的,这是真的。好的,好的。我已经删除了init我喜欢你的答案,但是如果
static dispatch\u once\u t once;
是在本地声明的,应用程序怎么知道在变量解除分配后的下一次不执行它呢?似乎它需要作为类变量存储。。。
dispatch_once
解决方案的真正问题是
static
跨越视图控制器的实例。此解决方案确保在应用程序进程的整个生命周期中只调用一次
myMethod
。@LyndseyScott不,这完全可以。它是一个静态变量,而不是局部变量。您可以阅读静态变量。这里有一个线程@rmaddy Correct,如果你拆下并重建视图控制器,dispatch_包装的代码将不会再次执行。在用户硬重设应用程序之前,它将不会再次执行!这在几乎所有情况下都是不希望出现的行为(包括本文中指定的情况)然后最好有一个您第一次设置的布尔标志。随后检查是否设置了该标志。从何处调用该标志?通过显示如何实际使用该标志来改进您的答案。问题围绕viewDidApearmethod@mohamadrezakoohkan即使视图已经加载,也可以多次调用viewdidApear他上面提出的问题是,他希望某件事情只执行一次。所以我要求他将逻辑从viewdidApear转换为viewdidLoad,因为viewdidLoad只调用了一次。如果他想做一些UI的事情,那么他可以在延迟后用perform selecter调用它,直到UI正确显示,这样他就可以避免在必须执行时出现额外的条件viewdidApear。希望它能解决您的问题。这段代码去哪里了?它还要求将
doSomeStuff
初始化为
YES
。这不是一个合适的解决方案。
doSomeStuff
不应该是公共的。视图控制器本身应该是唯一知道
doSomeStuff的类e> 应该设置