2
  • I have an App with 2 Targets: APP_TARGET1 & APP_TARGET2
  • I am Serializing an Object in my APP_TARGET1 and store it (sqlite, file)

     let data : NSData = NSKeyedArchiver.archivedDataWithRootObject(maptheme);
    
  • I am reading back the blob/file with APP_TARGET2 and try to deserialize the object.

     let temp=NSKeyedUnarchiver.unarchiveObjectWithData(data!);
    

-> I get the following error, which indicates, that serialized objects are depending on bundli-ids ?

Please someone tell me, that this is not true and that there is a workaround to have an apps-target, which writes the obejcts and another target which reads the objects.

Any help ?

NSKeyedUnarchiver.unarchiveObjectWithData(data!);

2016-01-15 10:21:11.476 APP_TARGET1[1684:38753] *** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (APP_TARGET2.MapTheme) for key (root); the class may be defined in source code or a library that is not linked'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010f5cce65 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010f043deb objc_exception_throw + 48
    2   Foundation                          0x000000010ec8835e -[NSCoder(Exceptions) __failWithExceptionName:errorCode:format:] + 0
    3   Foundation                          0x000000010ec88572 -[NSCoder(Exceptions) __failWithExceptionName:errorCode:format:] + 532
    4   Foundation                          0x000000010ebe3927 _decodeObjectBinary + 1659
    5   Foundation                          0x000000010ebe31a5 _decodeObject + 281
    6   Foundation                          0x000000010ec05931 +[NSKeyedUnarchiver unarchiveObjectWithData:] + 89
    7   WorldHistoryAtlasTest               0x000000010e748c11 _TF21WorldHistoryAtlasTest15loadThemeasBlobFSST6existsSb8mapThemeCS_8MapTheme_ + 3745
    8   WorldHistoryAtlasTest               0x000000010e781d9f _TFC21WorldHistoryAtlasTest22TimeLineViewController18load_map_meta_datafS0_FT_T_ + 207
    9   WorldHistoryAtlasTest               0x000000010e781231 _TFC21WorldHistoryAtlasTest22TimeLineViewController11viewDidLoadfS0_FT_T_ + 5889
    10  WorldHistoryAtlasTest               0x000000010e781cb2 _TToFC21WorldHistoryAtlasTest22TimeLineViewController11viewDidLoadfS0_FT_T_ + 34
    11  UIKit                               0x00000001102f9f98 -[UIViewController loadViewIfRequired] + 1198
    12  UIKit                               0x00000001102fa2e7 -[UIViewController view] + 27
    13  UIKit                               0x0000000110aa4f87 -[_UIFullscreenPresentationController _setPresentedViewController:] + 87
    14  UIKit                               0x00000001102c9f62 -[UIPresentationController initWithPresentedViewController:presentingViewController:] + 133
    15  UIKit                               0x000000011030cc8c -[UIViewController _presentViewController:withAnimationController:completion:] + 4002
    16  UIKit                               0x000000011030ff2c -[UIViewController _performCoordinatedPresentOrDismiss:animated:] + 489
    17  UIKit                               0x000000011030fa3b -[UIViewController presentViewController:animated:completion:] + 179
    18  WorldHistoryAtlasTest               0x000000010e6ba862 _TFC21WorldHistoryAtlasTest14ViewController12showTimelinefS0_FT_T_ + 594
    19  WorldHistoryAtlasTest               0x000000010e6b7ff2 _TFC21WorldHistoryAtlasTest14ViewController10loadModulefS0_FSST_ + 4002
    20  WorldHistoryAtlasTest               0x000000010e6d7036 _TFFFC21WorldHistoryAtlasTest14ViewController10loadModuleFS0_FSST_U2_FT_T_U0_FT_T_ + 86
    21  WorldHistoryAtlasTest               0x000000010e632d57 _TTRXFo__dT__XFdCb__dT__ + 39
    22  libdispatch.dylib                   0x0000000111d03e5d _dispatch_call_block_and_release + 12
    23  libdispatch.dylib                   0x0000000111d2449b _dispatch_client_callout + 8
    24  libdispatch.dylib                   0x0000000111d0c2af _dispatch_main_queue_callback_4CF + 1738
    25  CoreFoundation                      0x000000010f52cd09 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    26  CoreFoundation                      0x000000010f4ee2c9 __CFRunLoopRun + 2073
    27  CoreFoundation                      0x000000010f4ed828 CFRunLoopRunSpecific + 488
    28  GraphicsServices                    0x0000000113f94ad2 GSEventRunModal + 161
    29  UIKit                               0x0000000110163610 UIApplicationMain + 171
    30  WorldHistoryAtlasTest               0x000000010e7414fd main + 109
    31  libdyld.dylib                       0x0000000111d5992d start + 1
    32  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

UPDATE

Try to implement the Solution:

class BlobHandler: NSObject , NSKeyedUnarchiverDelegate{


let data:NSData? = NSData(bytes: point, length: Int(len));
                    //NSKeyedUnarchiver.set

                                  var mykeyedunarchiver:NSKeyedUnarchiver=NSKeyedUnarchiver(forReadingWithData: data!);
                mykeyedunarchiver.delegate = self;
                let temp=mykeyedunarchiver.decodeObject();

.... .... ....

   func unarchiver(_ unarchiver: NSKeyedUnarchiver, cannotDecodeObjectOfClassName name: String, originalClasses classNames: [String]) -> AnyClass? {

        print("I am in the delegated method !");
        return nil;

    }
  • I don't know to provide my data object to the unarchiver, when setting the delegate .
mcfly soft
  • 11,289
  • 26
  • 98
  • 202

1 Answers1

3

The problem is not the bundle id, the problem is that the classes compile differently because they are built into different targets.

You can deal with this by adding a delegate to the keyed unarchiver and implementing:

optional func unarchiver(_ unarchiver: NSKeyedUnarchiver, cannotDecodeObjectOfClassName name: String, originalClasses classNames: [String]) -> AnyClass?

so that you can check the requested class name and return the appropriate matching class in the current target.

Wain
  • 118,658
  • 15
  • 128
  • 151
  • Thanks for helping me bringen on the right path. (I accepted) I am happy that there is a solution, but I have problems implemnting it. Could you please take a look at my updated question "try to implement". I guess I have still some understanding problem. – mcfly soft Jan 15 '16 at 10:51
  • `optional` is part of the function definition, but shouldn't be in your implementation. Start by logging the `name` in the delegate method so you can see what you get. Then you need to write code to convert those names into `Class` instances to return (not instances of the class, just the class itself) – Wain Jan 15 '16 at 10:55
  • I guess, when delegate is called I can fill the code. (Hopefully :-) ) But I am confused on how to call unarchiveObjectWithData() with my unarchiver, because my mykeyedunarchiver has no method unarchiveObjectWithData. – mcfly soft Jan 15 '16 at 11:38
  • you need to use `init(forReadingWithData data: NSData)` and `decodeObject` – Wain Jan 15 '16 at 11:40
  • Thanks. mykeyedarchiver.decodeObject() I have found. But mykeyedarchiver.init( doesn't exist. How can I set the NSData. I went through all methods of context, but did not find. Any help ? – mcfly soft Jan 15 '16 at 13:14
  • Ignore my last. I am stupid. I saw what you meant with init :-) – mcfly soft Jan 15 '16 at 13:38
  • Could you please take a look at my code ? My delegate is not called. I have a breakpoint in my unarchiver, but its nbever called. – mcfly soft Jan 15 '16 at 13:44
  • looks generally ok, still see the optional there. no compile issues? – Wain Jan 15 '16 at 15:05
  • Sorry my fault. No optional is out. Did not update the answer correct. – mcfly soft Jan 15 '16 at 15:06
  • approach looks ok, you still get exception? – Wain Jan 15 '16 at 15:10
  • No I don't get an exception, but temp==nil and unarchiver is never called :-( – mcfly soft Jan 15 '16 at 15:52
  • add the other delegate methods to see if they're called. otherwise you may need to encode the object differently and use `encodeObject:forKey:` and `decodeObjectForKey:` – Wain Jan 15 '16 at 16:03
  • Thanks I just added the unarchiveDidFinish delegate, but this also is not called. I will start a new question, because conceptional you answered the question, Now its only a question of implementation. http://stackoverflow.com/questions/34824624/how-to-use-the-delegates-with-nskeyedunarchiver – mcfly soft Jan 16 '16 at 07:31
  • I am still not able to implement this. Delegate is now called after a clean and build of the project, but I have no clue on how to implement. I started a new question, if someone can help ? http://stackoverflow.com/questions/34856848/how-to-implement-the-unarchiver-delegate-for-overwriting-the-classname – mcfly soft Jan 18 '16 at 14:21