我正在寻找一种更短/更好的方法来从我的核心数据应用程序中的 NSSet 获取第一个对象

Posted

技术标签:

【中文标题】我正在寻找一种更短/更好的方法来从我的核心数据应用程序中的 NSSet 获取第一个对象【英文标题】:I'm looking for a shorter/better way to get the first object from and NSSet in my Core Data app 【发布时间】:2017-04-20 05:54:38 【问题描述】:

目前我有这个代码:

if let myPhoneNumbers = person.phoneNumbers?.allObjects as? [PhoneNumber] 
        for myPhoneNumber in myPhoneNumbers 
        mainPhoneNumber = myPhoneNumber.number
        break
    

这是正确的编码方式吗?我知道NSSet 是无序的,这可能是它没有自己的.first 实现的原因,例如:

person.phoneNumbers.first

但我认为我的代码不是最优雅的代码,也可能不是正确的 Swift 代码。

【问题讨论】:

对你的 NSSet 排序并取第一个对象 myPhoneNumbers 是一个数组,因此您可以使用 myPhoneNumbers.first 而不是使用 for 循环。 为什么你想要一个集合的第一个对象?你自己说的,NSSet是无序的,每次都会得到任意的电话号码,没有一致性 为什么每次循环时都将mainPhoneNumber 设置为另一个数字? 【参考方案1】:

我不知道为什么你会想要得到一个集合的任意“第一个”元素,但是你去吧:

let first = (person.phoneNumbers?.allObjects as? [PhoneNumber])?.first

这将产生更多/更少的随机结果。以下是我的建议:

将电话号码存储在一个数组中,以便保留用户对电话号码的排序。 我认为让用户确定主号码的构成要好得多。也许在Person 中存储对“主要”PhoneNumber 对象的引用。

【讨论】:

你是对的,获取第一个对象或 NSSet 中的任何对象与不保证顺序几乎相同,所以不妨改为调用set.anyObject() 有趣,我不知道anyObject。像这样的东西可能有什么用例? 我想要第一个号码出现的原因是我希望能够为每人分配一个以上的电话号码,在这个视图控制器中我不需要一个特定的号码,只需要一个出现,如果用户点击单元格,他会得到更多的细节。我希望用户输入的第一个数字是一种方便的方式首先出现。进一步考虑它,我可能会用别的东西代替它。我想对输入的电话号码进行一些排序,以防万一一个人有多个电话号码,其 type = "mobile" 谢谢! @PatrickMiron 但正如你自己所说,套装没有订购。用户输入电话号码的顺序绝对不会影响他们在集合中出现的顺序。 我试图查看是否可以返回第一个对象。在这种情况下这是没有意义的,你的权利。但这引发了我的另一个问题,它是否首先不会返回它插入到 NSSet 中的第一个对象,或者这也意味着它可能会也可能不会。 ...但是如果我理解上面 Mike Tavern 的评论,Core Data 会返回我一个 NSArray,我认为它是 NSSet 的子类,或者 fetchedObjects 实际上是一个 NSSet ...我要去咕咕咕!【参考方案2】:

在您的代码中,myPhoneNumbers 是一个数组,因此您可以使用 myPhoneNumbers.first 而不是循环。

if let myPhoneNumbers = person.phoneNumbers?.allObjects as? [PhoneNumber] 
    mainPhoneNumber = myPhoneNumbers.first

但是,正如已经指出的那样,您应该对您的集合施加某种顺序,以便执行此代码的结果对于任何给定的集合都是相同的。随意的结果通常是不好的。

既然您提到您正在使用 Core Data,我建议在您的 Person 实体上添加一个便利属性,以将电话号码作为排序数组返回。

如果您的实体看起来像这样......

class PhoneNumber: NSManagedObject 
    @NSManaged var number: String


class PersonEntity: NSManagedObject 
    @NSManaged var phoneNumbers: NSSet?

...您可以像这样创建便利属性:

class PersonEntity: NSManagedObject 

    @NSManaged var phoneNumbers: NSSet?

    // Arrays are often easier to work with than sets, 
    //  so provide a convenience property that returns
    //  phone numbers sorted
    var phoneNumbersArray: [PhoneNumber] 
        get 
            if let phoneNumbers = phoneNumbers 
                return (phoneNumbers.allObjects as! [PhoneNumber]).sorted() 
                    // here, sorting by phone number, but
                    // you can sort on whatever you want
                    $1.number > $0.number
                
            
            // return empty array if set is nil
            return [PhoneNumber]()
        
    

最后,用这样一行代码得到第一个数字:

mainPhoneNumber = person.phoneNumbersArray.first

我喜欢将这种类型的便利数组属性添加到我所有具有集合的实体中。在我看来,数组更容易使用。这里我选择在集合为 nil 时返回一个空数组而不是 nil 数组。如果您可以将 nil 和空电话集视为相同,则此方法有效。

另请注意,如果phoneNumbersArray 为空,.first 将返回 nil。

【讨论】:

很棒的评论。我可能不会在此实体中使用您的解释或代码,但我确实有另一个实体将获得此升级。呜呜!!谢谢 请注意,如果您要处理许多记录,因为当您只需要一个关系中的所有对象时,这将是非常低效的。 首先将电话号码存储为数组会更好。这一切都过于复杂了。 @Alexander 在 Core Data 中,使用 NSSet 表示一对多关系。 @MikeTaverne 哦,对,公平点。在那种情况下,我仍然遵从我的回答中的建议:I think it's much better for the user to determine what constitutes the main number. Perhaps store a reference to the "main" PhoneNumber object inside the Person.

以上是关于我正在寻找一种更短/更好的方法来从我的核心数据应用程序中的 NSSet 获取第一个对象的主要内容,如果未能解决你的问题,请参考以下文章

从 DataBinding 实例中查找类似视图

C# - 寻找一种简单的方法来解析两个不同表示之间的字符串值(数字和英语)

测试拖放文件到应用程序

有没有比 alloc 和 initWithFormat 更短的方法来从两种不同的数据类型创建 NSString?

在 Facebook 页面上发布的简单方法(不是个人资料,而是粉丝专页)

让我的查询更短、更快、更好