You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift iOS开发:Realm与ObjectMapper字符串数组映射问题

Fixing ObjectMapper_Realm Mapping for String Array to Realm List

Hey there! I see the issue you're running into—your JSON's authors field is an array of raw strings, but your current setup expects JSON objects to map to Author instances. Let's get this sorted out with a couple of straightforward solutions.

The Root Problem

Your existing ListTransform<Author> works when the JSON array contains objects (like [{"authorName": "Name FirstName"}]), but your JSON has just plain strings. We need a way to convert each string in the array into an Author object with its authorName set.


Solution 1: Custom Transform for String Array → List

This is the cleanest and most reusable approach. We'll create a custom TransformType that takes the string array, converts each entry into an Author instance, and even handles Realm primary key checks to avoid duplicate entries.

Step 1: Create the Custom Transform

Add this transform class to your project:

import ObjectMapper
import RealmSwift

class StringToAuthorListTransform: TransformType {
    // Define the types we're converting between
    typealias Object = List<Author>
    typealias JSON = [String]
    
    // Convert JSON string array to Realm List<Author>
    func transformFromJSON(_ value: Any?) -> List<Author>? {
        guard let authorNames = value as? [String] else {
            return nil
        }
        
        let authorsList = List<Author>()
        let realm = try? Realm()
        
        for name in authorNames {
            // Trim any whitespace (handles trailing commas/extra spaces in JSON)
            let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
            guard !trimmedName.isEmpty else { continue }
            
            // Reuse existing author if it exists in Realm (using primaryKey)
            if let existingAuthor = realm?.object(ofType: Author.self, forPrimaryKey: trimmedName) {
                authorsList.append(existingAuthor)
            } else {
                let newAuthor = Author()
                newAuthor.authorName = trimmedName
                authorsList.append(newAuthor)
            }
        }
        
        return authorsList
    }
    
    // Convert Realm List<Author> back to string array (for serialization)
    func transformToJSON(_ value: List<Author>?) -> [String]? {
        return value?.compactMap { $0.authorName }
    }
}

Step 2: Update the Book Mapping

Replace your existing authors mapping line in the Book class with this:

authors <- map[SerializationKeys.authors, StringToAuthorListTransform()]

Solution 2: Adjust the Author Class to Handle Raw Strings

If you prefer not to create a separate transform, you can modify your Author class to directly accept a string value instead of expecting a key-value pair.

Update the Author Class

import ObjectMapper
import RealmSwift

class Author: Object, Mappable {
    @objc dynamic var authorName: String?
    
    override class func primaryKey() -> String? {
        return "authorName"
    }
    
    convenience required init?(map: Map) {
        self.init()
        // Directly pull the string value from the map
        guard let name = map.currentValue as? String else {
            return nil
        }
        authorName = name.trimmingCharacters(in: .whitespacesAndNewlines)
    }
    
    func mapping(map: Map) {
        // Handle string input directly (no key needed)
        if let name = map.currentValue as? String {
            authorName = name.trimmingCharacters(in: .whitespacesAndNewlines)
        }
    }
}

Use a Modified List Transform

Then, in your Book mapping, use a ListTransform with a custom closure to convert strings to Author instances:

authors <- map[SerializationKeys.authors, ListTransform<Author>(transform: { (value: Any?) -> Author? in
    guard let name = value as? String else { return nil }
    let author = Author()
    author.authorName = name.trimmingCharacters(in: .whitespacesAndNewlines)
    return author
})]

Key Notes

  • Avoid Duplicate Authors: Since authorName is your primary key, Solution 1 checks Realm for existing authors first—this prevents creating duplicate Author objects for the same name.
  • Trim Whitespace: I added trimming to handle accidental spaces in the JSON (like the trailing comma in your example ["Name FirstName", ]).
  • Realm Write: Don't forget to wrap your save operation in a write block when mapping is done:
    let realm = try! Realm()
    try! realm.write {
        realm.add(books, update: .modified)
    }
    

内容的提问来源于stack exchange,提问作者Kassy Barb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:53:50