Updating the UI from another thread in iOS

本文探讨了在iOS应用开发中如何从非主线程安全地更新用户界面元素的问题。使用Grand Central Dispatch (GCD) API可以在后台线程完成任务后确保UI组件在主线程上进行更新,避免了潜在的崩溃和不稳定行为。
http://chritto.wordpress.com/2012/12/20/updating-the-ui-from-another-thread/

Apple’s UIKit is generally designed to be dealt with from within the main thread – operating with it from another thread can result in unpredictable results, including:

  • Everything may be fine
  • The user interface element may not be redrawn after your property changes
  • UIKit will give you a warning in the console, and throw an exception
  • The application will crash
  • The application won’t crash, and the UI will be left in an undefined state

The question then becomes: how can we update our user interface from a background thread? Utilising Apple’s Grand Central Dispatch APIs is one such way.

Suppose one of your UIViewControllers receives a message to update the background color of its main view. This method is called from a background thread (say, when a particular network packet arrives). We can attach ourselves to the main thread, make the call, and then return to our background thread so we can continue to process other network packets.

 
- ( void )updateBackgroundColor:(UIColor *)color
{
     dispatch_sync(dispatch_get_main_queue(), ^{
         self .view.backgroundColor = color;
     });
}

Taking a closer look at this, we have:

 
dispatch_sync(dispatch_queue_t queue, ^( void )block)

The “sync” part of the function name (as differentiated from “async”) means that the code that comes after the dispatch_sync call (and in this case, the code which sent the -updateBackgroundColor: message) will not continue to run until the work inside the block is done. This can be useful where the code that follows makes the assumption that the work inside the block has been done (e.g. if it were then to query the backgroundColor property of the view later on). Making the “async” version of the call throws the work to be done on a queue, and processes it later on, when the specified queue gets its chance to run again. It looks similar to the synchronous version:

1
dispatch_async(dispatch_queue_t queue, ^( void )block)

Many of the dispatch_* functions operate on dispatch queues. Here, we are operating on the main queue, which is connected with the main run loop (our UI thread):

 
dispatch_get_main_queue()

What about if we want to be able to call the same method, but from the UI thread? This creates a problem! The dispatch_sync function places its block of work to be done at the end of the main dispatch queue. It will then block until that work has been done. However, we’re already in the main thread, and until we return to the run loop, the block won’t be scheduled to run. This creates a deadlock – something we want to avoid. We can fix this with the following modification:

 
- ( void )updateBackgroundColor:(UIColor *)color
{
     if ([ NSThread isMainThread])
     {
         self .view.backgroundColor = color;
     }
     else
     {
         dispatch_sync(dispatch_get_main_queue(), ^{
             self .view.backgroundColor = color;
         });
     }
}

This is a little ugly, and duplicates the code – we can change it like this:

 
- ( void )updateBackgroundColor:(UIColor *)color
{
     dispatch_block_t work_to_do = ^{
         self .view.backgroundColor = color;
     }
     if ([ NSThread isMainThread])
     {
         work_to_do();
     }
     else
     {
         dispatch_sync(dispatch_get_main_queue(), work_to_do);
     }
}

Even better, we can throw this into a function which can be used elsewhere:

 
void RUN_ON_UI_THREAD(dispatch_block_t block)
{
     if ([ NSThread isMainThread])
         block();
     else
         dispatch_sync(dispatch_get_main_queue(), block);
}

so that our code is simplified to:

 
- ( void )updateBackgroundColor:(UIColor *)color
{
     RUN_ON_UI_THREAD(^{
         self .view.backgroundColor = color;
     });
}
<think>首先,用户的问题是关于Git的警告:"warning: Updating directories would lose untracked files, how to resolve"。我需要基于提供的引用和系统指令来回答。 系统指令: - 所有行内数学表达式用$...$格式。 - 独立公式用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 参考引用: - [^1]: 关于Git管理文件更改和暂存。 - [^2]: 关于git clean移除未跟踪文件。 - [^3]: 关于GIT_CEILING_DIRECTORIES。 - [^4]: 关于cherry-pick和git stash的使用。 - [^5]: 关于.gitignore和忽略文件。 用户的问题:Git警告"Updating directories would lose untracked files",用户想知道如何解决。 这个警告通常发生在执行像git checkout、git reset或git merge等命令时,Git检测到未跟踪的文件可能会被覆盖或丢失。用户需要确保这些文件被暂存、提交或忽略,以避免丢失。 基于引用: - 引用[^2]提到git clean移除未跟踪文件,但警告用户这可能永久删除文件。 - 引用[^4]展示了使用git stash来暂存更改,以便安全地进行操作。 - 引用[^5]提到忽略文件,使用.gitignore来避免跟踪某些文件。 可能的解决方案: 1. **暂存并提交文件**:如果文件需要保留,使用git add和git commit。 2. **忽略文件**:如果文件不需要跟踪,添加到.gitignore。 3. **使用git stash**:暂存更改,然后执行操作,再恢复更改。 4. **小心使用git clean**:但警告这可能删除文件。 回答结构: 1. **解释警告原因**:简要说明为什么出现这个警告。 2. **提供解决方案步骤**:逐步指导如何解决。 3. **添加引用标识**:在相关部分引用提供的材料。 4. **生成相关问题**:在最后添加相关问题。 确保使用中文回答。 生成相关问题: - 基于主题,如Git操作、文件管理。 最终回答: - 以清晰的结构呈现。</think>### Git警告“Updating directories would lose untracked files”的解决方案 在使用Git时,出现“warning: Updating directories would lose untracked files”警告,通常是因为您执行了某些操作(如`git checkout`、`git reset`或`git merge`),但Git检测到工作目录中存在未跟踪的文件(untracked files)。这些文件未被Git版本控制,如果继续操作,可能会被覆盖或永久删除。本回答将逐步指导您如何安全解决此问题,避免数据丢失。解决方案基于Git的核心机制:要么将文件纳入版本控制(暂存并提交),要么忽略它们(使用`.gitignore`),或临时暂存更改(使用`git stash`)。[^1] #### 步骤1: 理解警告原因 - **为什么会出现警告?** Git在更新目录时(例如切换分支或重置提交),会检查工作目录的状态。如果存在未跟踪的文件(即未通过`git add`添加到暂存区的文件),Git会警告您这些文件可能丢失,因为它们不在版本控制中。例如: - 执行`git checkout other-branch`时,如果当前分支有未跟踪文件,Git会提示此警告。 - 根本原因:Git的设计确保不会意外覆盖重要文件,但未跟踪文件被视为“临时”或“不重要”,因此需要您手动处理。[^2] #### 步骤2: 检查未跟踪文件 首先,确认哪些文件导致了警告。使用`git status`命令列出所有未跟踪文件: ```bash git status ``` 输出中会显示“Untracked files”部分,例如: ``` Untracked files: (use "git add <file>..." to include in what will be committed) path/to/untracked-file.txt another-file.log ``` 记录这些文件路径,它们是需要处理的对象。 #### 步骤3: 选择并执行解决方案 根据您的需求(是否保留文件),选择以下一种方法处理未跟踪文件: 1. **如果文件重要,需要纳入版本控制:暂存并提交文件** - 使用`git add`将文件添加到暂存区,然后提交: ```bash git add path/to/untracked-file.txt # 添加特定文件 git commit -m "Add untracked files to avoid loss" # 提交更改 ``` - 提交后,再执行原操作(如`git checkout other-branch`),警告将消失,因为文件现在在版本控制中。[^1] 2. **如果文件不重要,可以忽略:添加到`.gitignore`** - 创建或编辑`.gitignore`文件(在项目根目录),添加文件路径或模式以忽略它们: ```bash echo "path/to/untracked-file.txt" >> .gitignore # 忽略特定文件 echo "*.log" >> .gitignore # 忽略所有.log文件 ``` - 然后,运行`git status`确认文件不再显示为未跟踪。之后,原操作(如分支切换)将不会触发警告。[^5] 3. **如果文件是临时更改,需要暂存后恢复:使用`git stash`** - 此方法适用于您想保存文件但不立即提交的情况(例如,在切换分支前暂存当前工作): ```bash git stash push -u # -u选项包括未跟踪文件,将更改暂存 git stash list # 确认暂存成功 ``` - 执行原操作(如`git checkout other-branch`)。 - 操作完成后,恢复暂存的更改: ```bash git stash pop # 恢复最近一次暂存的更改 ``` 这确保了文件在操作过程中不会丢失,并在完成后还原。[^4] 4. **如果文件确实不需要,谨慎删除:使用`git clean`** - **警告**:此命令会永久删除未跟踪文件,仅在您确认文件无用后使用。先预览将被删除的文件: ```bash git clean -n # 预览删除操作(不实际执行) ``` - 如果确认删除,执行: ```bash git clean -f # 强制删除未跟踪文件 ``` 之后,警告会消失,但文件无法恢复。务必先备份重要文件。[^2] #### 步骤4: 验证解决方案 执行原命令(如`git checkout`)后,再次运行`git status`检查未跟踪文件是否已处理。如果警告消失,表示问题解决。如果仍有问题,检查`.gitignore`是否生效或是否有遗漏文件。 #### 预防措施 - **定期提交更改**:避免积累未跟踪文件,养成频繁使用`git add`和`git commit`的习惯。 - **使用`.gitignore`**:在项目初期添加忽略规则(如临时文件、日志文件),减少未跟踪文件产生。[^5] - **环境变量注意**:如果操作涉及慢速网络目录(如NFS),设置`GIT_CEILING_DIRECTORIES`环境变量可以优化性能,但不会直接影响此警告。[^3] 通过以上步骤,您可以安全解决Git警告,保护文件不被意外丢失。如果操作中遇到具体错误(如权限问题),请提供更多细节以便进一步诊断。[^1][^2][^4]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值