Couchbase Mobile and Swift

799 views
Skip to first unread message

Michael Gaylord

unread,
Jul 19, 2014, 4:16:37 AM7/19/14
to mobile-c...@googlegroups.com
I am a total newbie to Couchbase and Swift and I am trying to get a candidate architecture up and a running for a new app that I am working on. I think Couchbase would be a great fit, except for the fact that I am unable to get it working without crashing. This might be down to a few reasons, but just to sanity check, I just wanted to figure out if it is something I am doing wrong.

The following mapping function is resulting in a BAD_EXC error every time the emit function is called. The function is getting called from a view controller on startup. I have checked the parameters in the debugger and they are are pointing to valid references in memory. Here is the function that creates the query:

class func listEvents() -> CBLQuery? {
   
if let view:CBLView = DatabaseService.sharedInstance.database.viewNamed("events") {
     
if !view.mapBlock { //create the map block if it doesn't exist
        func mapBlock
(doc: [NSObject: AnyObject]!, emit: ((key: AnyObject, value: AnyObject!) -> ())?) {
         
if let type:AnyObject = doc["type"] {
           
if type.isKindOfClass(NSString.self) && (type as String) == Event.docType() {
             
if let key: AnyObject = doc["date"] {
               
if let emitFunc = emit {
                  emitFunc
(key: key, value: doc)
               
}
             
}
           
}
         
}
       
}
        view
.setMapBlock(mapBlock,
          reduceBlock
: nil,
          version
: "1")
     
}
     
return view.createQuery()
   
}
   
return nil
 
}


I have also tried rewriting the entire function in Objective-C and it works, so if nobody can help me, then I am going to put this one down to a bug in the Swift. If it is, I would  like to report the issue to Apple, but my understanding of how the Couchbase Mobile SDK works and Swift is still quite limited. If there is anybody out there that has managed to get Couchbase to work with Swift, it would be great if you could help me out. Or even better, if there is a sample project written in Swift on Github, that would be gold to me at this point.

Michael.

Jens Alfke

unread,
Jul 19, 2014, 12:19:16 PM7/19/14
to mobile-c...@googlegroups.com
On Jul 19, 2014, at 1:16 AM, Michael Gaylord <mjga...@gmail.com> wrote:

I am a total newbie to Couchbase and Swift and I am trying to get a candidate architecture up and a running for a new app that I am working on.

Yay! I have been wanting to get started with Swift myself and create a sample app for Couchbase Lite, but haven’t had the time. I was meaning to ask if anyone on the list had gotten CBL working in Swift.

The following mapping function is resulting in a BAD_EXC error every time the emit function is called.

It would be really helpful if you could post the backtrace (just enter ‘bt’ in the debugger console.)

The function is getting called from a view controller on startup. I have checked the parameters in the debugger and they are are pointing to valid references in memory. Here is the function that creates the query:

I don’t see any obvious bugs in that snippet, but I am even more of a Swift newbie than you.
I think a few things could be improved, though:
  • ‘doc’ can be typed as [String: AnyObject]! since the keys are guaranteed to be NSStrings.
  • You don’t need to cast ‘type’ to String before comparing it to Event.docType().
  • The ‘if let emitFunc = emit’ shouldn’t be necessary; you can just call emit directly.

—Jens

Michael Gaylord

unread,
Jul 20, 2014, 6:04:31 AM7/20/14
to mobile-c...@googlegroups.com
Thanks Jens!

Here is the backtrace as requested, Swift backtraces look really different to Objective-C ones:

* thread #7: tid = 0x1512c4, 0x00007fc0c3c79ca0, name = 'CouchbaseLite', stop reason = EXC_BAD_ACCESS (code=2, address=0x7fc0c3c79ca0)
    frame
#0: 0x00007fc0c3c79ca0
 
* frame #1: 0x00000001071e9fa7 Bookings`reabstraction thunk helper from @callee_owned (@in (key : Swift.AnyObject, value : Swift.ImplicitlyUnwrappedOptional<Swift.AnyObject>)) -> (@out ()) to @callee_owned (@owned Swift.AnyObject, @owned Swift.ImplicitlyUnwrappedOptional<Swift.AnyObject>) -> (@unowned ()) + 39 at Event.swift:38
    frame
#2: 0x00000001071e9e90 Bookings`Bookings.Event.(doc=<unavailable>, emit=<unavailable>) -> () -> Swift.Optional<ObjectiveC.CBLQuery>).(mapBlock #1) (Swift.ImplicitlyUnwrappedOptional<Swift.Dictionary<ObjectiveC.NSObject, Swift.AnyObject>>, Swift.Optional<(key : Swift.AnyObject, value : Swift.ImplicitlyUnwrappedOptional<Swift.AnyObject>) -> ()>) -> () + 6576 at Event.swift:39
    frame
#3: 0x00000001071ea1f0 Bookings`reabstraction thunk helper from @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional<Swift.Dictionary<ObjectiveC.NSObject, Swift.AnyObject>>, @owned Swift.ImplicitlyUnwrappedOptional<@objc_block (Swift.ImplicitlyUnwrappedOptional<Swift.AnyObject>, Swift.ImplicitlyUnwrappedOptional<Swift.AnyObject>) -> ()>) -> (@unowned ()) to @callee_unowned @objc_block (@unowned Swift.ImplicitlyUnwrappedOptional<ObjectiveC.NSDictionary>, @unowned Swift.ImplicitlyUnwrappedOptional<@objc_block (Swift.ImplicitlyUnwrappedOptional<Swift.AnyObject>, Swift.ImplicitlyUnwrappedOptional<Swift.AnyObject>) -> ()>) -> (@unowned ()) + 576 at Event.swift:45
    frame
#4: 0x00000001072185a8 Bookings`__32-[CBLView(.block_descriptor=0x0000000116aefae8) updateIndex]_block_invoke + 2180 at CBLView+Internal.m:312
    frame
#5: 0x000000010721061e Bookings`-[CBLDatabase(self=0x00007fc0c3d9a2c0, _cmd=<unavailable>, block=<unavailable>) _inTransaction:] + 113 at CBLDatabase+Internal.m:559
    frame
#6: 0x0000000107217c32 Bookings`-[CBLView(self=<unavailable>, _cmd=<unavailable>) updateIndex] + 242 at CBLView+Internal.m:191
    frame
#7: 0x000000010724aefd Bookings`-[CBLDatabase(self=<unavailable>, _cmd=<unavailable>, viewName=<unavailable>, options=CBLQueryOptions at 0x0000000116aefbe0, outLastSequence=0x0000000116aefc90, outStatus=0x0000000116aefc9c) queryViewNamed:options:lastSequence:status:] + 147 at CBLQuery.m:616
    frame
#8: 0x0000000107248f8e Bookings`__21-[CBLQuery runAsync:]_block_invoke(.block_descriptor=0x00007fc0c3c8c190, bgdb=<unavailable>) + 70 at CBLQuery.m:187
    frame
#9: 0x000000010721cb6f Bookings`__35-[CBL_Server tellDatabaseNamed:to:]_block_invoke(.block_descriptor=<unavailable>) + 69 at CBL_Server.m:132
    frame
#10: 0x00000001099f0032 Foundation`__NSThreadPerformPerform + 299
    frame
#11: 0x00000001094f70b1 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    frame
#12: 0x00000001094ec99d CoreFoundation`__CFRunLoopDoSources0 + 269
    frame
#13: 0x00000001094ebfd4 CoreFoundation`__CFRunLoopRun + 868
    frame
#14: 0x00000001094eba06 CoreFoundation`CFRunLoopRunSpecific + 470
    frame
#15: 0x00000001099f4912 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 275
    frame
#16: 0x000000010721c934 Bookings`-[CBL_Server runServerThread](self=0x00007fc0c3c8bcc0, _cmd=<unavailable>) + 312 at CBL_Server.m:113
    frame
#17: 0x00000001099f2a1d Foundation`__NSThread__main__ + 1194
    frame
#18: 0x000000010a6d3780 libsystem_pthread.dylib`_pthread_body + 131
    frame
#19: 0x000000010a6d36fd libsystem_pthread.dylib`_pthread_start + 176
    frame
#20: 0x000000010a6d194d libsystem_pthread.dylib`thread_start + 13


I don’t see any obvious bugs in that snippet, but I am even more of a Swift newbie than you.
think a few things could be improved, though:
  • ‘doc’ can be typed as [String: AnyObject]! since the keys are guaranteed to be NSStrings.
I can't type it to [String: AnyObject ]! because the emit function is declared in the Cloudbase API as ^(id key, id value). Since the Swift compiler is strongly-typed, it expects [AnyObject: AnyObject]!.
  • You don’t need to cast ‘type’ to String before comparing it to Event.docType().
Again, since Swift is strongly typed, the compiler won't accept type == Event.docType() since type is AnyObject. There might be other ways to make this more dynamic. Perhaps someone with a bit more experience using Swift knows how to make this a bit neater.  
  • The ‘if let emitFunc = emit’ shouldn’t be necessary; you can just call emit directly.
The emit block passed into the function is an optional, so it needs to be unwrapped when it gets called. I could alternatively unwrap it as it comes in, but if it is every nil, the app would crash. 

I am going to attempt to compile the Couchbase Lite framework with the same iOS SDK, up until now I've been using the precompiled binary. I will let you know how this pans out.

If I manage to get everything working, I am quite willing to upload my project as sample code.

Jens Alfke

unread,
Jul 20, 2014, 2:21:48 PM7/20/14
to mobile-c...@googlegroups.com

On Jul 20, 2014, at 3:04 AM, Michael Gaylord <mjga...@gmail.com> wrote:

> Here is the backtrace as requested, Swift backtraces look really different to Objective-C ones:

It definitely looks like it’s crashing trying to call the ‘emit’ block. Frame #2 is your map block, and frame #1 is a “thunk helper” (where “thunk” is a common term for a bit of auto-generated glue code used as an intermediary in a function call, particularly between languages.)

I don’t know whose error it is … it’s entirely possible that this is a Swift bug, since it’s a sort of unusual situation — a block pointer passed to a Swift closure, which is then calling back into that block.

> I can't type it to [String: AnyObject ]! because the emit function is declared in the Cloudbase API as ^(id key, id value). Since the Swift compiler is strongly-typed, it expects [AnyObject: AnyObject]!.

No, I meant that the ‘doc’ parameter to your map function could be typed as [String: AnyObject ]! … but that may not be possible because Swift probably interprets NSDictionary as [AnyObject:AnyObject]!. I wonder if there’s any kind of annotation I can add to the header to suggest to Swift that the key type will always be NSString?

> The emit block passed into the function is an optional, so it needs to be unwrapped when it gets called. I could alternatively unwrap it as it comes in, but if it is every nil, the app would crash.

It’s never nil. (Objective-C will crash, too, if it tries to call a nil block.)

—Jens

Mark Tracy

unread,
Jul 30, 2014, 5:31:13 PM7/30/14
to mobile-c...@googlegroups.com


On Saturday, July 19, 2014 1:16:37 AM UTC-7, Michael Gaylord wrote:

could help me out. Or even better, if there is a sample project written in Swift on Github, that would be gold to me at this point.

Michael.

Hello,
I too am pretty much a noob at Couchbase and Swift, but for my self-education project, I ported two of the sample iOS apps from Objective-C to Swift. So far, the only things I couldn't port were the data models because Swift does not support @dynamic properties (at least not yet).


You need to copy a current CouchbaseLite.framework into the projects. Let me know how it works for you.

Cheers,
Mark

Jens Alfke

unread,
Jul 30, 2014, 6:57:31 PM7/30/14
to mobile-c...@googlegroups.com

On Jul 30, 2014, at 2:31 PM, Mark Tracy <mark....@sci-mobile.com> wrote:

the only things I couldn't port were the data models because Swift does not support @dynamic properties (at least not yet).

Good point. I don’t know how to get around that. But I think this would also be a roadblock for using CoreData/NSManagedObject, so hopefully they’ll add support for dynamic properties.

—Jens

Mark Tracy

unread,
Jul 30, 2014, 10:35:42 PM7/30/14
to mobile-c...@googlegroups.com
Swift has a special construction for NSManaged properties, but it only works with CoreData.  Would using CBL as the persistence store for CoreData work?

Mark

Jens Alfke

unread,
Jul 31, 2014, 12:18:57 AM7/31/14
to mobile-c...@googlegroups.com

On Jul 30, 2014, at 7:35 PM, Mark Tracy <mark....@sci-mobile.com> wrote:

Swift has a special construction for NSManaged properties, but it only works with CoreData. 

Could you point me to any docs/information on this?

—Jens

Mirco Zeiss

unread,
Jul 31, 2014, 9:39:02 AM7/31/14
to mobile-c...@googlegroups.com
I got Couchbase Lite working with Swift. Thanks for creating the project by the way!

Here is some help to get you started. I just have to update the code to Xcode 6 Beta 4.

Mark Tracy

unread,
Jul 31, 2014, 1:42:18 PM7/31/14
to mobile-c...@googlegroups.com
"Using Swift with Cocoa and Objective-C" page 39
 

J. Chris Anderson

unread,
Sep 12, 2014, 12:05:45 PM9/12/14
to mobile-c...@googlegroups.com
Thanks for the resources in this thread. Especially the cheat sheet.


I missed something about Swift compiler settings for Bridge headers, so if you are stuck on the cheat sheet, click that link and see the screenshots.

Chris

Karel-Jan Van Haute

unread,
Oct 10, 2014, 5:22:53 AM10/10/14
to mobile-c...@googlegroups.com
Hey Mark

I just tried to build the todolist port to swift. 
But it gives a lot of error's (24).

Have you been able to build it correctly?

Thanks
Karel-Jan

Jens Alfke

unread,
Oct 10, 2014, 12:14:32 PM10/10/14
to mobile-c...@googlegroups.com

On Oct 10, 2014, at 2:22 AM, Karel-Jan Van Haute <kare...@gmail.com> wrote:

I just tried to build the todolist port to swift. 
But it gives a lot of error's (24).

If you have compile errors you should show us what they are, or we won't know how to help you.

—Jens
Reply all
Reply to author
Forward
0 new messages