Search code examples
objective-cswiftnsdictionary

Unrecognized selector sent to instance when trying to pass NSDictionary from swift class to objective c class


I have a class in swift which makes the dictionary using strings in keys and objects in values. eg let dict = ["key":value.key]. the value is always a string.

When i get the data in my objective c class, for one the object type is

_TtGCs26_SwiftDeferredNSDictionaryVs11AnyHashableP__$

and the code is expecting nsdictionary.

Now when the code -

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:dictionaryFromSwiftClass];

is executed, the program throws the error

********[1235:641121] -[__SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x280571380
//making dict in swift class

let dictForAddToCart:NSDictionary = 
[
    "assoc_prod":[

        ["assoc_prodID":"92",
         "assoc_prodValue":currentSelectedColor,
         "productInfo":[
             "code":productInfoColor.value(forKey: "code"),
             "id":productInfoColor.value(forKey: "id"),
             "image":productInfoColor.value(forKey: "image"),
             "label":productInfoColor.value(forKey: "label"),
             "optionslabel":productInfoColor.value(forKey: "optionslabel"),
             "price":productInfoColor.value(forKey: "price"),
             "qty":productInfoColor.value(forKey: "qty")]],

         ["assoc_prodID":"92",
         "assoc_prodValue":currentSelectedColor,
         "productInfo":[
             "code":productInfoColor.value(forKey: "code"),
             "id":productInfoColor.value(forKey: "id"),
             "image":productInfoColor.value(forKey: "image"),
             "label":productInfoColor.value(forKey: "label"),
             "optionslabel":productInfoColor.value(forKey: "optionslabel"),
             "price":productInfoColor.value(forKey: "price"),
             "qty":productInfoColor.value(forKey: "qty")]]
                  ]

     "productData":productData,
     "qty":currentSelectedQuantity

] as NSDictionary
//saving object in objective c class


- (void)saveCartArray:(NSArray *)arrayToSave {

    NSMutableArray *archiveArray = [NSMutableArray arrayWithCapacity:arrayToSave.count];

    for (NSMutableDictionary* productDic in arrayToSave) {
        NSData *productDicData = [NSKeyedArchiver archivedDataWithRootObject:productDic];

        [archiveArray addObject:productDicData];
    }

    NSUserDefaults *userData = [NSUserDefaults standardUserDefaults];
    [userData setObject:archiveArray forKey:@"cart"];

}
//NSLOG of arrayToSave-

{
        "assoc_prod" =         (
                        {
                "assoc_prodID" = 92;
                "assoc_prodValue" = 396;
                code = "********.Code.color";
                id = 92;
                image = "********.Image.empty";
                label = "********.Label.color";
                optionslabel = Nude;
                price = "280.0000";
                qty = "0.0000";
            },
                        {
                "assoc_prodID" = 180;
                "assoc_prodValue" = 388;
                code = "********.Code.size";
                id = 180;
                image = "********.Image.empty";
                label = "********.Label.size";
                optionslabel = 36;
                price = "280.0000";
                qty = "0.0000";
            }
        );
        productData =         {
            additionalParameters =             (
            );
            associatedProd = "someData";
            brand = "";
            categoryId = 378;
            description = "";
            image = "http://www.x.com/xyz.jpg";
            link = "";
            linkDownloads = "";
            name = some;
            position = 0;
            price = 280;
            productId = 1421;
            qty = 0;
            set = 0;
            shortDescription = "";
            sku = some;
            type = some;
            wsp = "";
        };
        qty = 1;
    }
)


Solution

  • I have a hunch this is a similar problem I answered here: https://stackoverflow.com/a/53501401/5329717

    Your case would be slightly different due to this:

    - (void)saveCartArray:(NSArray *)arrayToSave {
    
        NSMutableArray *archiveArray = [NSMutableArray arrayWithCapacity:arrayToSave.count];
    
        for (NSMutableDictionary* productDic in arrayToSave) {
            NSData *productDicData = [NSKeyedArchiver archivedDataWithRootObject:productDic];
    
            [archiveArray addObject:productDicData];
        }
    

    So essentially if I understand correctly the Swift bridged SwiftDeferredNSDictionary are elements in NSArray*. If you could extract

    NSData *productDicData = [NSKeyedArchiver archivedDataWithRootObject:productDic];
    

    to a separate method something like:

    -(NSData*)dictionaryToData:(NSDictionary*)dic {
        return [NSKeyedArchiver archivedDataWithRootObject:productDic];
    }
    

    And use my linked answer workaround:

    func mySwiftFunc(dic: Dictionary) {
         myObjcClassInstance.perform(#selector(NSSelectorFromString("dictionaryToData:"), with: dic as NSDictionary)
    }
    

    You could ensure you deal with "real" NSDictionary and avoid the implicit __SwiftValue bridging.