2014-11-13 30 views
3

我建立一个虚拟的iOS项目,以了解如何与斯威夫特核心数据执行验证。该项目的核心数据模型有一个名为Person一个实体,它包含两个属性:firstNamelastName。该项目是基于雨燕但是,为了启动它,我使用的Objective-C定义NSManagedObject子类:核心数据验证:从Objective-C的斯威夫特

Person.h

@interface Person : NSManagedObject 

@property (nonatomic, retain) NSString *firstName; 
@property (nonatomic, retain) NSString *lastName; 

@end 

Person.m

@implementation Person 

@dynamic firstName; 
@dynamic lastName;  

-(BOOL)validateFirstName:(id *)ioValue error:(NSError **)outError { 
    if (*ioValue == nil || [*ioValue isEqualToString: @""]) { 
     if (outError != NULL) { 
      NSString *errorStr = NSLocalizedStringFromTable(@"First name can't be empty", @"Person", @"validation: first name error"); 
      NSDictionary *userInfoDict = @{ NSLocalizedDescriptionKey : errorStr }; 
      NSError *error = [[NSError alloc] initWithDomain:@"Domain" code: 101 userInfo: userInfoDict]; 
      *outError = error; 
     } 
     return NO; 
    } 
    return YES; 
} 

@end 

人桥接-Header.h

#import "Person.h" 

在核心数据模型编辑器,我给自己定的实体类的数据模型督察里面所示:

class: Person 

我第一次启动这个项目,我在创建Person实例AppDelegateapplication:didFinishLaunchingWithOptions:方法用下面的代码:

if !NSUserDefaults.standardUserDefaults().boolForKey("isNotInitialLoad") { 
    let person = NSEntityDescription.insertNewObjectForEntityForName("Person", inManagedObjectContext: managedObjectContext!) as Person 
    person.firstName = "John" 
    person.lastName = "Doe" 

    var error: NSError? 
    if !managedObjectContext!.save(&error) { 
     println("Unresolved error \(error), \(error!.userInfo)") 
     abort() 
    } 

    NSUserDefaults.standardUserDefaults().setBool(true, forKey: "isNotInitialLoad") 
    NSUserDefaults.standardUserDefaults().synchronize() 
} 

该项目有一个UIViewController用下面的代码:

class ViewController: UIViewController { 

    var managedObjectContext: NSManagedObjectContext! 
    var person: Person! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     //Fetch the Person object 
     var error: NSError? 
     let fetchRequest = NSFetchRequest(entityName: "Person") 
     let array = managedObjectContext.executeFetchRequest(fetchRequest, error:&error) 
     if array == nil { 
      println("Unresolved error \(error), \(error!.userInfo)") 
      abort() 
     } 
     person = array![0] as Person 
    } 

    @IBAction func changeFirstName(sender: AnyObject) { 
     //Generate a random firstName 
     let array = ["John", "Jimmy", "James", "Johnny", ""] 
     person.firstName = array[Int(arc4random_uniform(UInt32(5)))] 

     var error: NSError? 
     if !managedObjectContext.save(&error) { 
      println("Unresolved error \(error), \(error!.userInfo)") 
      return 
     } 

     //If success, display the new person's name 
     println("\(person.firstName)" + " " + "\(person.lastName)") 
    } 

} 

changeFirstName:链接到UIButton。因此,无论何时点击此按钮,都会随机生成一个新的String并指定给person.firstName。如果这个新的String为空,则validateFirstName:error:生成NSError,并且保存操作失败。

这个伟大的工程,但是,为了有一个纯粹的斯威夫特项目,我已经决定删除​​Person.hPerson.mPerson-Bridging-Header.h,并将其与一个单一的斯威夫特文件替换:

class Person: NSManagedObject { 

    @NSManaged var firstName: String 
    @NSManaged var lastName: String 

    func validateFirstName(ioValue: AnyObject, error: NSErrorPointer) -> Bool { 
     if ioValue as? String == "" { 
      if error != nil { 
       let myBundle = NSBundle(forClass: self.dynamicType) 
       let errorString = myBundle.localizedStringForKey("First name can't be empty", value: "validation: first name error", table: "Person") 
       let userInfo = NSMutableDictionary() 
       userInfo[NSLocalizedFailureReasonErrorKey] = errorString 
       userInfo[NSValidationObjectErrorKey] = self 
       var validationError = NSError(domain: "Domain", code: NSManagedObjectValidationError, userInfo: userInfo) 
       error.memory = validationError 
      } 
      return false 
     } 

     return true 
    } 

} 

在核心数据模型编辑器,我也改变了实体类的数据模型督察里面所示:

class: Person.Person //<Project name>.Person 

现在的问题是,该项目的崩溃每当我打电话changeFirstName:。最奇怪的是,如果我在validateFirstName:内部放置一个断点,我可以看到这种方法从未被调用过。

我在做什么错?

+0

有你桥接Objective-C和斯威夫特的一个原因。为什么不直接在Swift中完成呢?我自己在桥接两种语言时遇到了一些问题,所以通常尽我所能避免在这些情况下桥接 – AdamM

+1

@AdamM:正如我理解的问题,它完全是“在Swift中完成”。 OP希望通过纯Swift实现来替代Objective-C代码。 –

+0

啊,我做了一个代码示例的快速扫描,并在该部分上进行了扫描。我的错! – AdamM

回答

5

我感到有点猜在这里,但(id *)ioValue参数映射到斯威夫特

ioValue: AutoreleasingUnsafeMutablePointer<AnyObject?> 

因此雨燕变异或许应该像

func validateFirstName(ioValue: AutoreleasingUnsafeMutablePointer<AnyObject?>, error: NSErrorPointer) -> Bool { 
    if let firstName = ioValue.memory as? String { 
     if firstName == "" { 
      // firstName is empty string 
      // ... 
     } 
    } else { 
     // firstName is nil (or not a String) 
     // ... 
    } 
    return true 
} 

更新斯威夫特2:

func validateFirstName(ioValue: AutoreleasingUnsafeMutablePointer<AnyObject?>) throws { 
    guard let firstName = ioValue.memory as? String where firstName != "" else { 
     // firstName is nil, empty, or not a String 
     let errorString = "First name can't be empty" 
     let userDict = [ NSLocalizedDescriptionKey: errorString ] 
     throw NSError(domain: "domain", code: NSManagedObjectValidationError, userInfo: userDict) 
    } 
    // firstName is a non-empty string 
} 

正如@SantaClaus正确注意到的,如果验证失败,验证功能现在必须 会引发错误。

+0

请注意,在Swift 2中,这些方法不会返回任何内容,而应该抛出一个错误(在swift 2中使用错误处理)。 –

+0

@SantaClaus:您完全正确,感谢您的通知! –

+0

非常有帮助,谢谢。 Swift 2版本使用'guard'可能更易读,而if-else则使用'if'语句。 – Stuart

0

苹果Core Data Programming Guide现在更新的斯威夫特3.下面是来自示例代码管理对象的生命周期>对象验证页面(memory已更名为pointee):

func validateAge(value: AutoreleasingUnsafeMutablePointer<AnyObject?>!) throws { 
    if value == nil { 
     return 
    } 

    let valueNumber = value!.pointee as! NSNumber 
    if valueNumber.floatValue > 0.0 { 
     return 
    } 
    let errorStr = NSLocalizedString("Age must be greater than zero", tableName: "Employee", comment: "validation: zero age error") 
    let userInfoDict = [NSLocalizedDescriptionKey: errorStr] 
    let error = NSError(domain: "EMPLOYEE_ERROR_DOMAIN", code: 1123, userInfo: userInfoDict) 
    throw error 
} 

编辑:这个例子并不完全正确。为了得到它的工作,我已经改变了AutoreleasingUnsafeMutablePointer<AnyObject?>来展开的可选和value?.pointeevalue.pointee

+0

您是否会如此善良,以使用您提到的在Swift 3中使用“展开的可选”的示例? – elysch

+0

不知道为什么,但我的验证方法永远不会被调用。将方法验证为足够了吗?还是应该验证? – elysch