ไม่พบคลาสย่อยเฉพาะของ NSManagedObject


136

ฉันกำลังพัฒนาแอพด้วย Core Data เมื่อฉันสร้างอินสแตนซ์โดยใช้:

let entity = NSEntityDescription.entityForName("User", inManagedObjectContext: appDelegate.managedObjectContext)
let user = User(entity: entity, insertIntoManagedObjectContext: appDelegate.managedObjectContext)

ฉันได้รับคำเตือนในบันทึก:

CoreData: warning: Unable to load class named 'User' for entity 'User'.  Class not found, using default NSManagedObject instead.

ฉันจะแก้ไขได้อย่างไร

และคำถามอื่นฉันจะกำหนดวิธีการอินสแตนซ์ในคลาสย่อย NSManagedObject ได้อย่างไร

แก้ไข:

ฉันได้ระบุคลาสของเอนทิตีเหมือนในภาพหน้าจอต่อไปนี้:

ป้อนคำอธิบายรูปภาพที่นี่


7
คุณมีคำนำหน้าชื่อคลาสเอนทิตีพร้อมชื่อโมดูลตามที่ระบุไว้ในการใช้งานคลาสข้อมูลหลักของวัตถุที่จัดการข้อมูลหรือไม่
Martin R

@MartinR: ดูอัปเดตคำถามของฉัน
MsrButterfly

2
คลาสควรเป็น "YourAppName.User" ดูเอกสารประกอบ (ลิงก์ในความคิดเห็นก่อนหน้าของฉัน)
Martin R

@ Martinin: ขอบคุณสำหรับความช่วยเหลือของคุณ มันได้ผล.
MsrButterfly

สิ่งที่ดีที่สุดคือการลบคลาสเหล่านั้นและสร้างใหม่ สิ่งนี้ใช้ได้กับฉัน
Abhishek

คำตอบ:


220

อัปเดตสำหรับ Xcode 7 (ขั้นสุดท้าย): การเตรียมชื่อโมดูลให้กับคลาส (เช่นใน Xcode 6 และเบต้ารุ่นแรก ๆ ของ Xcode 7) ไม่จำเป็นอีกต่อไป เอกสารประกอบของ Apple การปรับใช้คลาสย่อยของวัตถุข้อมูลที่จัดการหลักได้รับการอัปเดตตามนั้น

ตัวตรวจสอบตัวแบบข้อมูลมีสองฟิลด์ "ระดับ" และ "โมดูล" สำหรับเอนทิตี:

ป้อนคำอธิบายรูปภาพที่นี่

เมื่อคุณสร้างคลาสย่อยวัตถุที่มีการจัดการ Swift สำหรับเอนทิตีฟิลด์ "โมดูล" ถูกตั้งค่าเป็น "โมดูลผลิตภัณฑ์ปัจจุบัน" และด้วยการตั้งค่านี้การสร้างอินสแตนซ์จะทำงานได้ทั้งในแอปพลิเคชันหลักและในการทดสอบหน่วย คลาสย่อยของวัตถุที่ถูกจัดการจะต้องไม่ถูกทำเครื่องหมายด้วย@objc(classname)(สิ่งนี้ถูกตรวจสอบในhttps://stackoverflow.com/a/31288029/1187415 )

อีกวิธีหนึ่งคุณสามารถล้างข้อมูลในฟิลด์ "โมดูล" (จะแสดง "ไม่มี") และทำเครื่องหมายคลาสย่อยของวัตถุที่ถูกจัดการด้วย@objc(classname)(สิ่งนี้ถูกตรวจสอบในhttps://stackoverflow.com/a/31287260/1187415 )


หมายเหตุ:คำตอบนี้ถูกเขียนขึ้นครั้งแรกสำหรับ Xcode 6 มีการเปลี่ยนแปลงบางอย่างในรุ่น Xcode 7 รุ่นต่างๆที่เกี่ยวกับปัญหานี้ เนื่องจากเป็นคำตอบที่ได้รับการยอมรับพร้อม upvotes และลิงก์จำนวนมากฉันจึงพยายามสรุปสถานการณ์สำหรับรุ่นสุดท้ายของ Xcode 7

ผมทำทั้งสองของฉัน "การวิจัย" ของตัวเองและอ่านทุกคำตอบทั้งสองคำถามนี้และคำถามที่คล้ายกัน CoreData: คำเตือน: ไม่สามารถโหลดชื่อชั้น ดังนั้นการระบุแหล่งที่มาจะไปที่รายการทั้งหมดแม้ว่าฉันจะไม่ได้ระบุไว้โดยเฉพาะ


คำตอบก่อนหน้าสำหรับXcode 6 :

ดังที่ระบุไว้ในการใช้งานคลาสข้อมูลหลักของวัตถุที่จัดการข้อมูลคุณต้องนำหน้าชื่อคลาสเอนทิตีในฟิลด์คลาสในตัวตรวจสอบเอนทิตีโมเดลด้วยชื่อของโมดูลของคุณตัวอย่างเช่น "MyFirstSwiftApp.User"


2
อันนี้ใช้ได้สำหรับฉัน คำถาม: จะเกิดอะไรขึ้นถ้าข้อมูลแกนรวมอยู่ในเฟรมเวิร์กจะนำหน้าชื่อคลาสย่อย ManagedObject ได้อย่างไรเนื่องจากยังไม่มีแอปจริง
Allan Macatingrao

9
@Allan: คุณสามารถลอง@objc(ClassName)วิธีที่แนะนำในคำตอบของ Christer
Martin R

8
ใช้งานได้ แต่เมื่อฉันตั้งชื่อคลาสเป็น "APPNAME.User" ในตัวตรวจสอบเอนทิตีฉันไม่สามารถสร้างคลาสรุ่นใหม่ได้: Xcode ดูเหมือนจะสับสนโดยคำนำหน้าและสร้างชื่อไฟล์ / คลาสด้วยชื่อ APPNAME ฉันพลาดอะไรไปรึเปล่า?
Pascal Bourque

1
จะเกิดอะไรขึ้นถ้าคุณได้รับข้อผิดพลาดนี้ใน Objective-C เมื่อใช้ข้อมูลหลักในไลบรารีแบบคงที่
George Taskos

1
@Suragch: ตอนนี้ฉันได้อัปเดตคำตอบแล้วฉันหวังว่าทุกอย่างจะถูกต้องในขณะนี้
Martin R

62

เช่นเดียวกับบันทึกด้านข้าง ฉันมีปัญหาเดียวกัน และทั้งหมดที่ฉันต้องทำคือเพิ่ม@objc(ClassName)ไฟล์คลาสของฉัน

ตัวอย่าง:

@objc(Person)
class Person { }

และนั่นช่วยแก้ไขปัญหาของฉัน


1
คุณกำหนด typealias (<% ProjectName%>. Person -> Person) ใน Objective-C ด้วยวิธีการดังกล่าวดังนั้นจึงสามารถใช้งานได้
MsrButterfly

ดูเหมือนว่าแอปเปิ้ลลืมที่จะแปลงให้เป็นสวิฟท์อย่างเต็มที่ .. ไม่รู้ว่าทำไม แต่สิ่งนี้ทำให้ฉันค่อนข้างนุ่มนวล
JiříZahálka

7
สิ่งนี้มีประโยชน์อย่างยิ่งหากคุณมีโครงการที่มีเป้าหมายหลายเป้าหมายโดยที่แต่ละเป้าหมายใช้โมเดล CoreData ร่วมกัน ในกรณีเหล่านี้เป็นไปไม่ได้ที่จะนำหน้าชื่อคลาสด้วยตัวระบุเป้าหมายเนื่องจากแสดงรูปแบบซีดีที่เป็นประโยชน์ต่อหนึ่งในเป้าหมายเท่านั้น
djbp

@djbp แล้ว "ทำไมล่ะ" ฉันอยากรู้ ฉันชอบแนวคิดของการกำหนดเนมสเปซ แต่มันทำให้ฉันต้องการทิ้ง MacBook ของฉันออกไปนอกหน้าต่าง (ฉันมีแอพที่มีส่วนขยายและประสบปัญหานี้เมื่อเรียกใช้ส่วนขยาย) จะต้องมีวิธี "ถูกต้อง" ในการทำเช่นนี้กับ namespaces ฉันก็ไม่สามารถคิดออก
S'pht'Kr

ใช่สิ่งนี้ทำงานสำหรับฉันเมื่อทำงานกับโมเดลข้อมูลที่แชร์ในเวิร์กสเปซ
naz

31

คำตอบที่ได้รับการยอมรับสำหรับคำถามนี้ช่วยฉันแก้ปัญหาเดียวกัน แต่ฉันมีข้อแม้ที่ฉันคิดว่าจะเป็นประโยชน์กับผู้อื่น หากชื่อโครงการ (โมดูล) ของคุณมีช่องว่างคุณต้องแทนที่ช่องว่างด้วยเครื่องหมายขีดล่าง ตัวอย่างเช่น:

เอนทิตี: MyEntity Class: My_App_Name.MyClass


ว่าฉันกำลังมองหา! ไชโย!
manosim

เมื่อเราตั้งชื่อคลาสด้วย AppName.ClassName Xcode 9 จะลบจุดนั้นออกและสร้างคลาสโดยไม่มีจุด ดังนั้นนี่จะไม่อยู่ใน Xcode 9 * อีกต่อไป
yo2bh


9

ขึ้นอยู่กับว่าคุณกำลังทำงานเป็น App VS ทดสอบปัญหาสามารถเป็นไปได้ว่าแอปที่กำลังมองหาและเมื่อมันทำงานการทดสอบก็มองเป็น<appName>.<entityName> <appName>Tests.<entityName>วิธีแก้ปัญหาที่ฉันใช้ในขณะนี้ (Xcode 6.1) คือการไม่เติมClassฟิลด์ใน CoreData UI และทำในรหัสแทน

รหัสนี้จะตรวจสอบว่าคุณกำลังทำงานเป็น App managedObjectClassNameเทียบกับการทดสอบและใช้ชื่อโมดูลที่เหมาะสมและปรับปรุง

lazy var managedObjectModel: NSManagedObjectModel = {
    // The managed object model for the application. This property is not optional...
    let modelURL = NSBundle.mainBundle().URLForResource("Streak", withExtension: "momd")!
    let managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)!

    // Check if we are running as test or not
    let environment = NSProcessInfo.processInfo().environment as [String : AnyObject]
    let isTest = (environment["XCInjectBundle"] as? String)?.pathExtension == "xctest"

    // Create the module name
    let moduleName = (isTest) ? "StreakTests" : "Streak"

    // Create a new managed object model with updated entity class names
    var newEntities = [] as [NSEntityDescription]
    for (_, entity) in enumerate(managedObjectModel.entities) {
        let newEntity = entity.copy() as NSEntityDescription
        newEntity.managedObjectClassName = "\(moduleName).\(entity.name)"
        newEntities.append(newEntity)
    }
    let newManagedObjectModel = NSManagedObjectModel()
    newManagedObjectModel.entities = newEntities

    return newManagedObjectModel
}()

1
ฉันลองวิธีการแก้ปัญหาของคุณ แต่ฉันได้รับ "ข้อผิดพลาดร้ายแรง: องค์ประกอบ NSArray ไม่ตรงกับประเภทองค์ประกอบ Swift Array" เมื่อส่ง NSManagedObject ไปยังคลาสจริง จริง ๆ แล้วไม่ได้เมื่อหล่อตัวเอง แต่เมื่อพยายามเข้าไปในวง
Rodrigo Ruiz

1
ตัวอย่างนั้นไม่ทำงานหากคุณมีการสืบทอดในรูปแบบของคุณ สำหรับเอนทิตีใหม่ทุกครั้งที่คุณต้องทำซ้ำมากกว่าไซต์ย่อยและอัปเดตด้วยเอนทิตีใหม่ที่คุณสร้างขึ้น
Anton

8

หากคุณใช้ยัติภังค์ในชื่อโปรเจคของคุณเช่น "My-App" ให้ใช้เครื่องหมายขีดล่างแทนเครื่องหมายยัติภังค์เช่น "My_App.MyManagedObject" โดยทั่วไปให้ดูที่ชื่อของไฟล์ xcdatamodeld และใช้คำนำหน้าเช่นเดียวกับในชื่อนั้น เช่น "My_App_1.xcdatamodeld" ต้องการคำนำหน้า "My_App_1"


1
ว้าว. ขอบคุณขอบคุณขอบคุณ. ฉันสนใจที่จะรู้ว่าในเอกสารของ Apple ที่นักเก็ตตัวน้อยอยู่
ที่ไหน

5

วิธีนี้อาจช่วยให้ผู้ที่ประสบปัญหาเดียวกัน ฉันอยู่กับ Swift 2 และ Xcode 7 beta 2

วิธีการแก้ปัญหาในกรณีของฉันคือการแสดงความคิดเห็นออกมาใน@objc(EntityName)EntityName.swift


3

ฉันมีคำเตือนแบบเดียวกันถึงแม้ว่าแอพของฉันจะทำงานได้ดี ปัญหาคือเมื่อรัน Editor> Create NSManagedObject Subclass บนหน้าจอสุดท้ายฉันใช้ตำแหน่งกลุ่มเริ่มต้นโดยไม่มีเป้าหมายที่แสดงหรือตรวจสอบซึ่งบันทึก subclass ในไดเรกทอรี MyApp ด้านบนที่ MyApp.xcodeproj ตั้งอยู่
คำเตือนหายไปเมื่อฉันเปลี่ยนกลุ่มให้อยู่ในโฟลเดอร์ย่อย MyApp และตรวจสอบเป้าหมาย MyApp


2

คำตอบข้างต้นมีประโยชน์ การตรวจสติอย่างรวดเร็วนี้อาจช่วยคุณประหยัดเวลา เข้าสู่โครงการ> สร้างเฟส> รวบรวมแหล่งที่มาและลบ xcdatamodeld และไฟล์โมเดลของคุณด้วยปุ่ม "-" จากนั้นเพิ่มกลับคืนด้วยปุ่ม "+" สร้างใหม่ - ที่อาจดูแลได้


2

ระวังสิ่งที่คุณเพิ่มเป็นคำนำหน้า: แอพของฉันเรียกว่า "ABC-def" และ Xcode ได้แปลง "-" เป็น "_"

เพื่อความปลอดภัยในการค้นหาโปรแกรมค้นหาไฟล์โครงการของคุณและดูสิ่งที่มันบอกว่าสำหรับรูปแบบข้อมูลของคุณ (ตัวอย่างเช่น "ABC_def.xcdatamodeld") และใช้สิ่งที่เขียนตรงนั้น !!!


1

คำตอบข้างต้นช่วยให้ฉันแก้ปัญหาต่าง ๆ ที่เชื่อมโยงกับ Objective-C (อาจช่วยคน):

หากคุณปรับโครงสร้างชื่อนิติบุคคลใหม่อย่าลืมเปลี่ยน "คลาส" ใน "แผงเครื่องมือไฟฟ้า" ด้วย


0

คำตอบข้างต้นช่วยฉัน แต่นี่อาจช่วยใครซักคน ถ้าอย่างฉันคุณทำและยังมีปัญหาอย่าลืม 'ทำความสะอาดโครงการของคุณ' สำหรับ XCode8 ผลิตภัณฑ์> ล้าง จากนั้นเรียกใช้อีกครั้ง


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.