- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我试图在完成或取消后重新启动 NSBlockOperation
,但出现错误?任何人都知道错误在哪里?谢谢
let imageURLs = ["http://www.planetware.com/photos-large/F/france-paris-eiffel-tower.jpg",
"http://adriatic-lines.com/wp-content/uploads/2015/04/canal-of-Venice.jpg",
"http://algoos.com/wp-content/uploads/2015/08/ireland-02.jpg",
"http://bdo.se/wp-content/uploads/2014/01/Stockholm1.jpg"]
class Downloader {
class func downloadImageWithURL(url:String) -> UIImage! {
let data = NSData(contentsOfURL: NSURL(string: url)!)
return UIImage(data: data!)
}
}
class ViewController: UIViewController {
@IBOutlet weak var imageView1: UIImageView!
var indeX = 0
let operation1 = NSBlockOperation()
var queue = NSOperationQueue()
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func didClickOnStart(sender: AnyObject) {
queue = NSOperationQueue()
operation1.addExecutionBlock { () -> Void in
for _ in imageURLs {
if !self.operation1.cancelled {
let img1 = Downloader.downloadImageWithURL(imageURLs[self.indeX])
NSOperationQueue.mainQueue().addOperationWithBlock({
self.imageView1.image = img1
print("indeX \(self.indeX)")
self.indeX++
})
}
}
}
queue.addOperation(operation1)
}
@IBAction func didClickOnCancel(sender: AnyObject) {
self.queue.cancelAllOperations()
print(operation1.finished)
}
}
Output
indeX 0
false
indeX 1
2016-07-20 02:00:26.157 ConcurrencyDemo[707:15846] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSBlockOperation addExecutionBlock:]: blocks cannot be added after the operation has started executing or finished'
*** First throw call stack:
(
0 CoreFoundation 0x000000010c94be65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010e68bdeb objc_exception_throw + 48
2 Foundation 0x000000010cd369fe -[NSBlockOperation addExecutionBlock:] + 356
3 ConcurrencyDemo 0x000000010c766edd _TFC15ConcurrencyDemo14ViewController15didClickOnStartfS0_FPSs9AnyObject_T_ + 253
4 ConcurrencyDemo 0x000000010c767086 _TToFC15ConcurrencyDemo14ViewController15didClickOnStartfS0_FPSs9AnyObject_T_ + 54
5 UIKit 0x000000010d16a194 -[UIApplication sendAction:to:from:forEvent:] + 92
6 UIKit 0x000000010d56b7b7 -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 152
7 UIKit 0x000000010d16a194 -[UIApplication sendAction:to:from:forEvent:] + 92
8 UIKit 0x000000010d2d96fc -[UIControl sendAction:to:forEvent:] + 67
9 UIKit 0x000000010d2d99c8 -[UIControl _sendActionsForEvents:withEvent:] + 311
10 UIKit 0x000000010d2d9b43 -[UIControl _sendActionsForEvents:withEvent:] + 690
11 UIKit 0x000000010d2d8af8 -[UIControl touchesEnded:withEvent:] + 601
12 UIKit 0x000000010d1d949b -[UIWindow _sendTouchesForEvent:] + 835
13 UIKit 0x000000010d1da1d0 -[UIWindow sendEvent:] + 865
14 UIKit 0x000000010d188b66 -[UIApplication sendEvent:] + 263
15 UIKit 0x000000010d162d97 _UIApplicationHandleEventQueue + 6844
16 CoreFoundation 0x000000010c877a31 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
17 CoreFoundation 0x000000010c86d95c __CFRunLoopDoSources0 + 556
18 CoreFoundation 0x000000010c86ce13 __CFRunLoopRun + 867
19 CoreFoundation 0x000000010c86c828 CFRunLoopRunSpecific + 488
20 GraphicsServices 0x0000000110f5ead2 GSEventRunModal + 161
21 UIKit 0x000000010d168610 UIApplicationMain + 171
22 ConcurrencyDemo 0x000000010c76906d main + 109
23 libdyld.dylib 0x000000010f19492d start + 1
24 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
最佳答案
让我概述一系列备选方案。第一个只是解决您问题中的直接战术问题,后两个是进一步改进,越来越复杂。
您不能在操作开始后调用 addExecutionBlock
。因此,只需创建一个新的 Operation
。
例如:
class ViewController: UIViewController {
@IBOutlet weak var imageView1: UIImageView!
weak var downloadOperation: Operation? // make this weak
var queue = OperationQueue()
let imageURLs: [String] = ...
@IBAction func didClickOnStart(_ sender: Any) {
downloadOperation?.cancel() // you might want to stop the previous one if you restart this
let operation = BlockOperation {
for (index, imageURL) in self.imageURLs.enumerate() {
guard let cancelled = self.downloadOperation?.cancelled where !cancelled else { return }
let img1 = Downloader.downloadImageWithURL(imageURL)
OperationQueue.main.addOperation {
self.imageView1.image = img1
print("index \(index)")
}
}
}
queue.addOperation(operation)
downloadOperation = operation
}
@IBAction func didClickOnCancel(_ sender: Any) {
downloadOperation?.cancel()
}
}
值得注意的是,连续加载图像会导致不必要的缓慢。您可以同时加载它们,例如:
class ViewController: UIViewController {
@IBOutlet weak var imageView1: UIImageView!
var queue: OperationQueue = {
let _queue = OperationQueue()
_queue.maxConcurrentOperationCount = 4
return _queue
}()
let imageURLs: [String] = ...
@IBAction func didClickOnStart(_ sender: Any) {
queue.cancelAllOperations()
let completionOperation = BlockOperation {
print("all done")
}
for (index, imageURL) in self.imageURLs.enumerate() {
let operation = BlockOperation {
let img1 = Downloader.downloadImageWithURL(imageURL)
OperationQueue.main.addOperation {
self.imageView1.image = img1
print("index \(index)")
}
}
completionOperation.addDependency(operation)
queue.addOperation(operation)
}
OperationQueue.main.addOperation(completionOperation)
}
@IBAction func didClickOnCancel(_ sender: Any) {
queue.cancelAllOperations()
}
}
即使那样也有问题。另一个问题是,当您“取消”时,它可能会继续尝试下载当前正在下载的资源,因为您没有使用可取消的网络请求。
更好的方法是将下载(将通过 URLSession
执行)包装在它自己的异步 Operation
子类中,并使其可取消,例如:
class ViewController: UIViewController {
var queue: OperationQueue = {
let _queue = OperationQueue()
_queue.maxConcurrentOperationCount = 4
return _queue
}()
let imageURLs: [URL] = ...
@IBAction func didClickOnStart(_ sender: Any) {
queue.cancelAllOperations()
let completion = BlockOperation {
print("done")
}
for url in imageURLs {
let operation = ImageDownloadOperation(url: url) { result in
switch result {
case .failure(let error):
print(url.lastPathComponent, error)
case .success(let image):
OperationQueue.main.addOperation {
self.imageView1.image = img1
print("index \(index)")
}
}
}
completion.addDependency(operation)
queue.addOperation(operation)
}
OperationQueue.main.addOperation(completion)
}
@IBAction func didClickOnCancel(_ sender: AnyObject) {
queue.cancelAllOperations()
}
}
在哪里
/// Simple image network operation
class ImageDownloadOperation: DataOperation {
init(url: URL, session: URLSession = .shared, networkCompletionHandler: @escaping (Result<UIImage, Error>) -> Void) {
super.init(url: url, session: session) { result in
switch result {
case .failure(let error):
networkCompletionHandler(.failure(error))
case .success(let data):
guard let image = UIImage(data: data) else {
networkCompletionHandler(.failure(DownloadError.notImage))
return
}
networkCompletionHandler(.success(image))
}
}
}
}
/// Simple network data operation
///
/// This can be subclassed for image-specific operations, JSON-specific operations, etc.
class DataOperation: AsynchronousOperation {
var downloadTask: URLSessionTask?
init(url: URL, session: URLSession = .shared, networkCompletionHandler: @escaping (Result<Data, Error>) -> Void) {
super.init()
downloadTask = session.dataTask(with: url) { data, response, error in
defer { self.complete() }
guard let data = data, let response = response as? HTTPURLResponse, error == nil else {
networkCompletionHandler(.failure(error!))
return
}
guard 200..<300 ~= response.statusCode else {
networkCompletionHandler(.failure(DownloadError.invalidStatusCode(response)))
return
}
networkCompletionHandler(.success(data))
}
}
override func main() {
downloadTask?.resume()
}
override func cancel() {
super.cancel()
downloadTask?.cancel()
}
}
/// Asynchronous Operation base class
///
/// This class performs all of the necessary KVN of `isFinished` and
/// `isExecuting` for a concurrent `NSOperation` subclass. So, to developer
/// a concurrent NSOperation subclass, you instead subclass this class which:
///
/// - must override `main()` with the tasks that initiate the asynchronous task;
///
/// - must call `completeOperation()` function when the asynchronous task is done;
///
/// - optionally, periodically check `self.cancelled` status, performing any clean-up
/// necessary and then ensuring that `completeOperation()` is called; or
/// override `cancel` method, calling `super.cancel()` and then cleaning-up
/// and ensuring `completeOperation()` is called.
public class AsynchronousOperation: Operation {
override public var isAsynchronous: Bool { return true }
private let stateLock = NSLock()
private var _executing: Bool = false
override private(set) public var isExecuting: Bool {
get {
stateLock.withCriticalScope { _executing }
}
set {
willChangeValue(forKey: "isExecuting")
stateLock.withCriticalScope { _executing = newValue }
didChangeValue(forKey: "isExecuting")
}
}
private var _finished: Bool = false
override private(set) public var isFinished: Bool {
get {
stateLock.withCriticalScope { _finished }
}
set {
willChangeValue(forKey: "isFinished")
stateLock.withCriticalScope { _finished = newValue }
didChangeValue(forKey: "isFinished")
}
}
/// Complete the operation
///
/// This will result in the appropriate KVN of isFinished and isExecuting
public func complete() {
if isExecuting {
isExecuting = false
}
if !isFinished {
isFinished = true
}
}
override public func start() {
if isCancelled {
isFinished = true
return
}
isExecuting = true
main()
}
override public func main() {
fatalError("subclasses must override `main`")
}
}
extension NSLock {
/// Perform closure within lock.
///
/// An extension to `NSLock` to simplify executing critical code.
///
/// - parameter block: The closure to be performed.
func withCriticalScope<T>(block: () throws -> T) rethrows -> T {
lock()
defer { unlock() }
return try block()
}
}
关于ios - [NSBlockOperation addExecutionBlock :]: blocks cannot be added after the operation has started executing or finished,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38468535/
我有一个场景,我们必须通过 Azure AD 对企业用户进行身份验证,但通过 Azure AD B2C 对外部用户进行身份验证——所有这些都来自同一个登录屏幕。 有一些 Web 应用程序将共享此功能。
在使用 Azure AD B2C 和 Azure AD B2B 之前,我通常会将应用程序添加到我们租户的 Azure AD 中,并且 Office 365 用户可以使用其帐户 (SSO) 访问应用程序
当 Azure Active Directory 信任访问本地 Active Directory 用户时,我们是否可以使用本地 AD 用户名(域限定的 sam 帐户名称,例如:cosmos\brahm
什么是在网站上展示广告的好托管广告管理器? 我听说过OpenX ,但从未使用过。 最佳答案 我们使用名为 Ad Serving Solutions http://www.adservingsoluti
是否可以将用户从云 Azure Active Directory 同步到本地 AD? On Premises 这里有点错误,因为它实际上是 Azure 中的虚拟网络,带有 Windows Server
我正在关注这里的答案:Multi-Tenant Azure AD Auth in Azure AD B2C with Custom Policies 以及这里的演练:https://github.co
我正在尝试使用/common Azure AD 端点在 Azure AD B2C 中使用 Azure AD Auth。根据How to sign in any Azure Active Directo
来自 Mercurial 文档: The manifest is the file that describes the contents of the repository at a particu
我正在尝试将 firebase admob 与 React Native 集成到我的应用程序中,一切都适用于 testID横幅 ('ca-app-pub-3940256099942544/293473
我有一个应用程序需要根据其本地 AD 通用名称来过滤权限。几点注意事项: Azure AD Connect 正在 OnPrem AD 和 Azure 之间同步数据 我已成功将登录用户的组信息从 Azu
我正在使用 blogspot 平台并在我的网站上使用了 Google Adsense。我想对齐一个自动 Adsense 广告,它根本不居中,而带有代码的广告则完全没有问题。它只是自动广告,有人可以帮助
为什么redirect URL必须完全匹配?在域级别进行匹配是否不足以提供适当的安全性? 如果我有数百条路径怎么办? 示例网址: https://myawesomesite.com https://m
我即将创建一个新的 Azure AKS 群集,并且希望将 AKS 与 Azure Key Vault 集成。几个月前,在学习阶段,我看到需要使用Azure AD pod管理的身份来做到这一点,但现在我
我正在尝试配置我的 Azure AD 以同步我的本地 AD DS,如果在 Microsoft Azure AD 中添加任何用户,它应该自动在我的本地 AD 中注册。 我已创建 Azure AD 并配置
我有大约 50 个用户的 Azure AD。这些用户是我们购买Office365时创建的。假设 Azure AD 上的域是 example.com。 ([email protected])在本地,我们
我正在尝试获取组 Azure AD 的名称,Azure 登录 (openId) 后的内部 token 我收到 json 格式的组 ID,但我需要组名称。 登录后的Json: Claims 尝试使用Gr
我们希望将 Azure AD B2C 用于我们的 Web 应用程序,以允许用户使用其公司 ADFS 帐户登录。 根据Azure Active Directory B2C: Add ADFS as a
首先,我无法了解为什么需要这些数据,也无法了解有关网络的细节。您必须相信我,除了运行 LDAP 查询的 PowerShell 脚本之外,没有其他方法可以获取这些数据。 我正在使用具有多个林和多个域的网
我是一个相当新的 PS 用户...正在寻求有关 powershell 脚本的帮助来获取用户所属的安全组列表。 描述我需要什么: 我有包含许多用户(samaccountnames)的输入列表(txt 文
我有两个要存储在目录中以供我的应用程序使用的声明。这些内容不可供用户编辑,但可用于应用程序从 token 中读取。 内置策略可以检索声明,但是,使用自定义策略检索这些声明没有取得任何成功。 通读文章“
我是一名优秀的程序员,十分优秀!