在我的项目中,我同时拥有 Objective-C 和 Swift 代码。我有一些对象具有包含 block 的属性来清理一些 UITableView 配置。在 Objective-C 中使用它可以工作,但在使用 Swift 时会崩溃。
我已将问题减少到尽可能小的程度,同时仍可重现。
// in Objective-C
@interface MyClass : NSObject
@property (copy, nonatomic) NSString* (^block)();
- (NSString *)callTheBlock;
@end
@implementation MyClass
- (NSString *)callTheBlock {
if (self.block) {
return self.block();
} else {
return @"There is no spoon";
}
}
@end
// In Swift
// I actually have this in my AppDelegate to run when the app starts, but that shouldn't matter
class AppDelegate: UIResponder, UIApplicationDelegate {
var myClass: MyClass?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
self.myClass = MyClass()
self.myClass?.block = { () -> String in
NSLog("In Closure")
var string = "String From Closure" // <-- "po string" correctly prints the string
return string // <-- This is where it crashes
}
let output = self.myClass?.callTheBlock()
NSLog("\(output)")
...
}
我最终得到了 EXC_BAD_ACCESS,所以我猜它与不应该发布的东西有关,但我不知道我做错了什么。
堆栈跟踪非常少:
* thread #1: tid = 0x4a8b6a, 0xbff2d9c8, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0xbff2d9c8)
* frame #0: 0xbff2d9c8
frame #1: 0xbff2d9e0
但是,如果我将 block 更改为需要一个字符串作为参数:
// MyClass
@property (copy, nonatomic) NSString* (^block)(NSString *string);
// Using it in Swift
self.myClass?.block = { (inString: String!) -> String in
NSLog("In Closure")
var string = "String From Closure"
return string
}
我得到了一个更有说服力的堆栈跟踪:
* thread #1: tid = 0x4a9a38, 0x01b07e63 libobjc.A.dylib`objc_release + 19, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x40000013)
frame #0: 0x01b07e63 libobjc.A.dylib`objc_release + 19
* frame #1: 0x0005e442 MyApp`MyApp.AppDelegate.(inString=Some) -> (ObjectiveC.UIApplication, didFinishLaunchingWithOptions : Swift.Optional<ObjectiveC.NSDictionary>) -> Swift.Bool).(closure #1) + 594 at AppDelegate.swift:22
frame #2: 0x0005e4ad MyApp`reabstraction thunk helper from @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) to @callee_owned (@in Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@out Swift.ImplicitlyUnwrappedOptional<Swift.String>) + 77 at AppDelegate.swift:19
frame #3: 0x0005cbaa MyApp`partial apply forwarder for reabstraction thunk helper from @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) to @callee_owned (@in Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@out Swift.ImplicitlyUnwrappedOptional<Swift.String>) + 90 at AppDelegate.swift:0
frame #4: 0x0005e5e7 MyApp`reabstraction thunk helper from @callee_owned (@in Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@out Swift.ImplicitlyUnwrappedOptional<Swift.String>) to @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) + 71 at AppDelegate.swift:19
frame #5: 0x0005ce64 MyApp`partial apply forwarder for reabstraction thunk helper from @callee_owned (@in Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@out Swift.ImplicitlyUnwrappedOptional<Swift.String>) to @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) + 132 at AppDelegate.swift:0
frame #6: 0x0005e7ee MyApp`reabstraction thunk helper from @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) to @callee_unowned @objc_block (@unowned Swift.ImplicitlyUnwrappedOptional<ObjectiveC.NSString>) -> (@autoreleased Swift.ImplicitlyUnwrappedOptional<ObjectiveC.NSString>) + 478 at AppDelegate.swift:19
frame #7: 0x0008fa3f MyApp`-[MyClass callTheBlock](self=0x7beadc50, _cmd=0x000edee6) + 143 at MyClass.m:38
frame #8: 0x0005bcf8 MyApp`MyApp.AppDelegate.application (application=0x7c160390, launchOptions=None, self=0x7c162d50)(ObjectiveC.UIApplication, didFinishLaunchingWithOptions : Swift.Optional<ObjectiveC.NSDictionary>) -> Swift.Bool + 1544 at AppDelegate.swift:24
frame #9: 0x0005cf55 MyApp`@objc MyApp.AppDelegate.application (MyApp.AppDelegate)(ObjectiveC.UIApplication, didFinishLaunchingWithOptions : Swift.Optional<ObjectiveC.NSDictionary>) -> Swift.Bool + 101 at AppDelegate.swift:0
frame #10: 0x0090d14f UIKit`-[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 309
frame #11: 0x0090daa1 UIKit`-[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1810
frame #12: 0x00912667 UIKit`-[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 824
frame #13: 0x00926f92 UIKit`-[UIApplication handleEvent:withNewEvent:] + 3517
frame #14: 0x00927555 UIKit`-[UIApplication sendEvent:] + 85
frame #15: 0x00914250 UIKit`_UIApplicationHandleEvent + 683
frame #16: 0x03b9df02 GraphicsServices`_PurpleEventCallback + 776
frame #17: 0x03b9da0d GraphicsServices`PurpleEventCallback + 46
frame #18: 0x01cf6ca5 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
frame #19: 0x01cf69db CoreFoundation`__CFRunLoopDoSource1 + 523
frame #20: 0x01d2168c CoreFoundation`__CFRunLoopRun + 2156
frame #21: 0x01d209d3 CoreFoundation`CFRunLoopRunSpecific + 467
frame #22: 0x01d207eb CoreFoundation`CFRunLoopRunInMode + 123
frame #23: 0x00911d9c UIKit`-[UIApplication _run] + 840
frame #24: 0x00913f9b UIKit`UIApplicationMain + 1225
frame #25: 0x0005dbae MyApp`top_level_code + 78 at AppDelegate.swift:12
frame #26: 0x0005dbeb MyApp`main + 43 at AppDelegate.swift:0
frame #27: 0x024e3701 libdyld.dylib`start + 1
编辑:我最初认为它与被异步调用有关,但像这样之后直接调用它是可重现的,所以我修复了代码和堆栈跟踪以反射(reflect)这一点。
最佳答案
我在弹出文档的帮助下弄明白了!
在处理 Objective-C 时,大多数事情都需要 !。我很确定这是因为 Objective-C 没有像 Swift 中那样的可选概念。
而不是将我的闭包定义为:
... self.myClass?.block = { (inString: String!) -> String in ...
将其更改为:
... self.myClass?.block = { (inString: String!) -> String! in ...
这是有道理的,因为这是弹出文档中推荐的内容。
关于ios - 当作为 Objective-C block 调用时,Swift 闭包崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25522064/
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
当我在Rails控制台中按向上或向左箭头时,出现此错误:irb(main):001:0>/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/rb-readline-0.4.2/lib/rbreadline.rb:4269:in`blockin_rl_dispatch_subseq':invalidbytesequenceinUTF-8(ArgumentError)我使用rvm来管理我的ruby安装。我正在使用=>ruby-2.0.0-p247[x86_64]我使用bundle来管理我的gem,并且我有rb-readline(0.4.2)(人们推荐的最少
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
我正在尝试为我的iOS应用程序设置cocoapods但是当我执行命令时:sudogemupdate--system我收到错误消息:当前已安装最新版本。中止。当我进入cocoapods的下一步时:sudogeminstallcocoapods我在MacOS10.8.5上遇到错误:ERROR:Errorinstallingcocoapods:cocoapods-trunkrequiresRubyversion>=2.0.0.我在MacOS10.9.4上尝试了同样的操作,但出现错误:ERROR:Couldnotfindavalidgem'cocoapods'(>=0),hereiswhy:U
我是Ruby的新手,有些闭包逻辑让我感到困惑。考虑这段代码:array=[]foriin(1..5)array[5,5,5,5,5]这对我来说很有意义,因为i被绑定(bind)在循环之外,所以每次循环都会捕获相同的变量。使用每个block可以解决这个问题对我来说也很有意义:array=[](1..5).each{|i|array[1,2,3,4,5]...因为现在每次通过时都单独声明i。但现在我迷路了:为什么我不能通过引入一个中间变量来修复它?array=[]foriin1..5j=iarray[5,5,5,5,5]因为j每次循环都是新的,我认为每次循环都会捕获不同的变量。例如,这绝对
print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上
我希望这些值匹配。当shell脚本由于某些错误条件而退出时(因此返回非零值),它们不匹配。壳$?返回1,ruby$?返回256。>>%x[lskkr]ls:kkr:Nosuchfileordirectory=>"">>puts$?256=>nil>>exitHadoop:~Madcap$lskkrls:kkr:NosuchfileordirectoryHadoop:~Madcap$echo$?1 最佳答案 在Ruby中$?是一个Process::Status实例。打印$?等同于调用$?.to_s,这等同于$?.to_i.to_s(来
代码:threads=[]Thread.abort_on_exception=truebegin#throwexceptionsinthreadssowecanseethemthreadseputs"EXCEPTION:#{e.inspect}"puts"MESSAGE:#{e.message}"end崩溃:.rvm/gems/ruby-2.1.3@req/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:478:inload_missing_constant':自动加载常量MyClass时检测到循环依赖稍加研究后,