使某些代码只运行一次

Posted

技术标签:

【中文标题】使某些代码只运行一次【英文标题】:Making some code only run once 【发布时间】:2012-03-05 18:10:48 【问题描述】:

我有一些代码只想在我的 MainViewController 中运行一次。它应该在用户每次启动应用程序时运行,但仅在 MainViewController 加载后运行。

我不想在-(void)applicationDidFinishLaunching:(UIApplication *)application 中运行它。

这是我的想法:

MainViewController.h

@interface IpadMainViewController : UIViewController <UISplitViewControllerDelegate> 
    BOOL hasRun;


@property (nonatomic, assign) BOOL hasRun;

MainViewController.m

@synthesize hasRun;

-(void)viewDidLoad 
    [super viewDidLoad];
    if (hasRun == 0) 
        // Do some stuff
        hasRun = 1;
    

有什么想法吗?

【问题讨论】:

运行-(void)applicationDidFinishLaunching:(UIApplication *)application 或您的代码有什么问题?或者,如果您不分配 MainViewCONtroller,它无论如何都会运行一次 每次激活一次(即启动时一次,从后台返回时一次),还是每次加载到内存中一次? 【参考方案1】:

Swift 1,2:

static var token: dispatch_once_t = 0

dispatch_once(&token) 
  NSLog("Do it once")

Objective-C

static dispatch_once_t once;
dispatch_once(&once, ^ 
  NSLog(@"Do it once");
);

Swift 3,4:

dispatch_once 在 Swift 中不再可用。在 Swift 中,您可以使用 延迟初始化的全局变量或静态属性并得到相同的 dispatch_once 提供的线程安全和调用一次保证 Apple doc

let myGlobal =  … global contains initialization in a call to a closure … ()
_ = myGlobal  // using myGlobal will invoke 
              // the initialization code only the first time it is used.

【讨论】:

+1;对于这个任务,GCD 是比在你的类中保持 BOOL 状态更干净的选择 请注意,这是每个加载到内存中的应用程序一次。该代码将不会为正在创建的此类的另一个实例再次运行(这有点我最近),也不会在应用程序从挂起返回前台时再次运行。 很好的答案。这感觉比我最初的想法优雅得多。我学到了一些东西。谢谢! @JoshCaswell 好点,你知道无论如何要“重置” GCD 或类的实例,以便在某个时候再次调用它吗?我可以打电话给[[ClassName alloc] init]; 来“重置”它吗? 可以重置once 令牌,@RazorSharp: ***.com/questions/10930044/…,尽管那时我会说你应该只使用另一个应该的机制重置,就像 Dylan 对 BOOL 属性的建议一样。【参考方案2】:

我认为该代码没有任何问题。我喜欢使用 BOOL(就像您所做的那样),然后分配 YES/NO 或 TRUE/FALSE,以便代码读取得更好。我会将 TRUE 分配给 didFinishLaunching 中的 firstRun,并在代码执行后将其设置为 FALSE。在我的代码中,这些类型的条件通常如下所示:

@synthesize firstRun;

-(void)viewDidLoad 
   [super viewDidLoad];
    if (firstRun) 
        // code to run only once goes here
        firstRun = FALSE;
    

【讨论】:

另一个推荐 Grand Central Dispatch 的答案可以说是一种更好的方法。另一方面,作为 BSD 级别的技术,考虑到这是一个“基本”问题,它的学习曲线相当陡峭。如果你想按照你的要求做,这段代码比你原来的代码稍微干净一些——如果你想尝试一种更高级的任务管理方法,GCD 非常强大。【参考方案3】:

可能的变化(Swift 5):

// Whether this is the first code run since app (re)started
var firstRun: Bool = true

public final class Foo 
    public init() 
        if firstRun 
            // Code that has to be run only once goes
            // HERE
            firstRun = false
        
    

【讨论】:

【参考方案4】:

由于没有dispatch_once_t insswift 3及以上,我们可以使用惰性初始化全局变量

创建一个惰性全局变量

lazy var doOnlyOnce: () -> Void = 
    .. add code to run only once here ..
    return 
()

运行代码:

_ = doOnlyOnce

【讨论】:

【参考方案5】:

使用 Swift2.0、Xcode 7.0

var token: dispatch_once_t = 0

override func viewDidLoad() 
    super. viewDidLoad()
    dispatch_once(&token) 
        println("This is printed only on the first call to test()")
    
    println("This is printed for each call to test()")

【讨论】:

【参考方案6】:

对于 Swift2.2、Xcode 7.3:

static var token: dispatch_once_t = 0

dispatch_once(&YourClassName.token) 
  NSLog("Do it once")

注意“YourClassName.token

【讨论】:

以上是关于使某些代码只运行一次的主要内容,如果未能解决你的问题,请参考以下文章

如何使一行代码在循环中运行一次,并且只运行下一行代码,直到前一行运行一次?

线程同步代码块:两个客户往一个银行存钱,每人存三十次一次存一百。 模拟银行存钱功能,时时银行现金数。

如何使自定义标签中的代码块仅在第一次调用该标签时运行?

jQuery onChange 只运行一次

一次一密加密解密算法

Linux守护进程实现程序只运行一次