gpt4 book ai didi

ios - NSFetchedResultsController 字符串最后一个字符的排序描述符

转载 作者:行者123 更新时间:2023-11-28 12:51:02 24 4
gpt4 key购买 nike

你如何设置一个 NSSortDescriptor 将按属性排序(但它的最后一个字符?)

例如,如果我有以下条形码...

0000000005353

0000000000224

0000000433355

它应该使用最后一个字符按升序或降序排序。所以就像这个例子中的 3,4,5。这将创建节标题 3、4、5。

我当前的代码给我一个错误,说“在索引 7 处获取的对象有一个乱序的部分名称‘9’。对象必须按部分名称排序。这告诉我我搞砸了排序。到了解更多请查看代码,因为我在核心数据模型上使用 transient 属性。

想法是“numberendsection”应该按照我之前描述的那样从数字末尾开始排序。

我描述的其他两种类型现在工作得很好。

Inventory+CoreDataProperties.swift

import Foundation
import CoreData

extension Inventory {

@NSManaged var addCount: NSNumber?
@NSManaged var barcode: String?
@NSManaged var currentCount: NSNumber?
@NSManaged var id: NSNumber?
@NSManaged var imageLargePath: String?
@NSManaged var imageSmallPath: String?
@NSManaged var name: String?
@NSManaged var negativeCount: NSNumber?
@NSManaged var newCount: NSNumber?
@NSManaged var store_id: NSNumber?
@NSManaged var store: Store?

//This is used for A,B,C ordering...
var lettersection: String? {
let characters = name!.characters.map { String($0) }
return characters.first?.uppercaseString
}

//This is used for 1,2,3 ordering... (using front of barcode)
var numbersection: String? {
let characters = barcode!.characters.map { String($0) }
return characters.first?.uppercaseString
}

//This is used for 0000000123 ordering...(uses back number of barcode)
var numberendsection: String? {
let characters = barcode!.characters.map { String($0) }
return characters.last?.uppercaseString
}

}

InventoryController.swift -(仅显示相关部分)

import UIKit
import CoreData
import Foundation

class InventoryController: UIViewController, UISearchBarDelegate, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate {

//Create fetchedResultsController to handle Inventory Core Data Operations
lazy var fetchedResultsController: NSFetchedResultsController = {
return self.setFetchedResultsController()
}()

func setFetchedResultsController() -> NSFetchedResultsController{
let inventoryFetchRequest = NSFetchRequest(entityName: "Inventory")

var primarySortDescriptor = NSSortDescriptor(key: "name", ascending: true)//by default assume name.

if(g_appSettings[0].indextype=="numberfront"){
primarySortDescriptor = NSSortDescriptor(key: "barcode", ascending: true)
}else if(g_appSettings[0].indextype=="numberback"){
primarySortDescriptor = NSSortDescriptor(key: "barcode", ascending: true)
}

//let secondarySortDescriptor = NSSortDescriptor(key: "barcode", ascending: true)

inventoryFetchRequest.sortDescriptors = [primarySortDescriptor]

let storefilter = g_appSettings[0].selectedStore!
let predicate = NSPredicate(format: "store = %@", storefilter) //This will ensure correct data relating to store is showing

inventoryFetchRequest.predicate = predicate

//default assume letter section
var frc = NSFetchedResultsController(
fetchRequest: inventoryFetchRequest,
managedObjectContext: self.moc,
sectionNameKeyPath: "lettersection",
cacheName: nil)

if(g_appSettings[0].indextype=="numberfront"){
frc = NSFetchedResultsController(
fetchRequest: inventoryFetchRequest,
managedObjectContext: self.moc,
sectionNameKeyPath: "numbersection",
cacheName: nil)
}else if(g_appSettings[0].indextype=="numberback"){
frc = NSFetchedResultsController(
fetchRequest: inventoryFetchRequest,
managedObjectContext: self.moc,
sectionNameKeyPath: "numberendsection",
cacheName: nil)
}

frc.delegate = self

return frc
}

实体图

enter image description here

enter image description here

实体 + 核心数据截图

enter image description here

出现错误的截图和代码

enter image description here

Inventory.swift

enter image description here

** Inventory.swift 整个文件 **

import UIKit
import CoreData
import Foundation

class InventoryController: UIViewController, UISearchBarDelegate, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate {

//Create fetchedResultsController to handle Inventory Core Data Operations
lazy var fetchedResultsController: NSFetchedResultsController = {
return self.setFetchedResultsController()
}()

func setFetchedResultsController() -> NSFetchedResultsController{
let inventoryFetchRequest = NSFetchRequest(entityName: "Inventory")

var primarySortDescriptor = NSSortDescriptor(key: "name", ascending: true)//by default assume name.

print("primarySortDescriptor...")

if(g_appSettings[0].indextype=="numberfront"){
primarySortDescriptor = NSSortDescriptor(key: "barcode", ascending: true)
}else if(g_appSettings[0].indextype=="numberback"){
primarySortDescriptor = NSSortDescriptor(key: "barcode", ascending: true)
}

print("set primarySortDescriptor")

//let secondarySortDescriptor = NSSortDescriptor(key: "barcode", ascending: true)

inventoryFetchRequest.sortDescriptors = [primarySortDescriptor]

print("set sort descriptors to fetch request")

var storefilter : Store? = nil

if(g_appSettings[0].selectedStore != nil){
storefilter = g_appSettings[0].selectedStore
let predicate = NSPredicate(format: "store = %@", storefilter!) //This will ensure correct data relating to store is showing
inventoryFetchRequest.predicate = predicate
}

//default assume letter section
var frc = NSFetchedResultsController(
fetchRequest: inventoryFetchRequest,
managedObjectContext: self.moc,
sectionNameKeyPath: "lettersection",
cacheName: nil)

if(g_appSettings[0].indextype=="numberfront"){
frc = NSFetchedResultsController(
fetchRequest: inventoryFetchRequest,
managedObjectContext: self.moc,
sectionNameKeyPath: "numbersection",
cacheName: nil)
}else if(g_appSettings[0].indextype=="numberback"){
frc = NSFetchedResultsController(
fetchRequest: inventoryFetchRequest,
managedObjectContext: self.moc,
sectionNameKeyPath: "numbersection",
cacheName: nil)
}

print("set the frc")

frc.delegate = self

return frc
}

@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var inventoryTable: UITableView!



var moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext //convinience variable to access managed object context

// Start DEMO Related Code
var numberIndex = ["0","1","2","3","4","5","6","7","8","9"]
var letterIndex = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]

var previousNumber = -1 //used so we show A,A, B,B, C,C etc for proper testing of sections

func createInventoryDummyData(number: Int) -> Inventory{
let tempInventory = NSEntityDescription.insertNewObjectForEntityForName("Inventory", inManagedObjectContext: moc) as! Inventory
if(number-1 == previousNumber){
tempInventory.name = "\(letterIndex[number-2])-Test Item # \(number)"
previousNumber = -1//reset it again
}else{
tempInventory.name = "\(letterIndex[number-1])-Test Item # \(number)"
previousNumber = number //set previous letter accordingly
}
tempInventory.barcode = "\(number)00000000\(number)"
tempInventory.currentCount = 0
tempInventory.id = number
tempInventory.imageLargePath = "http://website.tech//uploads/inventory/7d3fe5bfad38a3545e80c73c1453e380.png"
tempInventory.imageSmallPath = "http://website.tech//uploads/inventory/7d3fe5bfad38a3545e80c73c1453e380.png"
tempInventory.addCount = 0
tempInventory.negativeCount = 0
tempInventory.newCount = 0
tempInventory.store_id = 1 //belongs to same store for now

//Select a random store to belong to 0 through 2 since array starts at 0
let aRandomInt = Int.random(0...2)
tempInventory.setValue(g_storeList[aRandomInt], forKey: "store") //assigns inventory to one of the stores we created.

return tempInventory
}

func createStoreDummyData(number:Int) -> Store{
let tempStore = NSEntityDescription.insertNewObjectForEntityForName("Store", inManagedObjectContext: moc) as! Store

tempStore.address = "100\(number) lane, Miami, FL"
tempStore.email = "store\(number)@centraltire.com"
tempStore.id = number
tempStore.lat = 1.00000007
tempStore.lng = 1.00000008
tempStore.name = "Store #\(number)"
tempStore.phone = "123000000\(number)"

return tempStore
}

// End DEMO Related Code

override func viewDidLoad() {
super.viewDidLoad()

print("InventoryController -> ViewDidLoad -> ... starting inits")

// // Do any additional setup after loading the view, typically from a nib.
// print("InventoryController -> ViewDidLoad -> ... starting inits")
//
//First check to see if we have entities already. There MUST be entities, even if its DEMO data.
let inventoryFetchRequest = NSFetchRequest(entityName: "Inventory")
let storeFetchRequest = NSFetchRequest(entityName: "Store")

do {
let storeRecords = try moc.executeFetchRequest(storeFetchRequest) as? [Store]
//Maybe sort descriptor here? But how to organize into sectioned array?

if(storeRecords!.count<=0){
g_demoMode = true
print("No store entities found. Demo mode = True. Creating default store entities...")

var store : Store //define variable as Store type

for index in 1...3 {
store = createStoreDummyData(index)
g_storeList.append(store)
}

//save changes for the stores we added
do {
try moc.save()
print("saved to entity")
}catch{
fatalError("Failure to save context: \(error)")
}
}

let inventoryRecords = try moc.executeFetchRequest(inventoryFetchRequest) as? [Inventory]
//Maybe sort descriptor here? But how to organize into sectioned array?

if(inventoryRecords!.count<=0){
g_demoMode = true
print("No entities found for inventory. Demo mode = True. Creating default entities...")

var entity : Inventory //define variable as Inventory type

for index in 1...52 {
let indexFloat = Float(index/2)+1
let realIndex = Int(round(indexFloat))
entity = createInventoryDummyData(realIndex)
g_inventoryItems.append(entity)
}

//save changes for inventory we added
do {
try moc.save()
print("saved to entity")
}catch{
fatalError("Failure to save context: \(error)")
}

print("finished creating entities")
}

}catch{
fatalError("bad things happened \(error)")
}




//perform fetch we need to do.
do {
try fetchedResultsController.performFetch()
} catch {
print("An error occurred")
}

print("InventoryController -> viewDidload -> ... finished inits!")
}

override func viewWillAppear(animated: Bool) {
print("view appearing")
//When the view appears its important that the table is updated.

//Look at the selected Store & Use the LIST of Inventory Under it.

//Perform another fetch again to get correct data~
do {
//fetchedResultsController. //this will force setter code to run again.
print("attempting fetch again, reset to use lazy init")
fetchedResultsController = setFetchedResultsController() //sets it again so its correct.
try fetchedResultsController.performFetch()
} catch {
print("An error occurred")
}


inventoryTable.reloadData()//this is important to update correctly for changes that might have been made
}

// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
print("inventoryItemControllerPrepareForSegueCalled")

if segue.identifier == "inventoryInfoSegue" {
let vc = segue.destinationViewController as! InventoryItemController
if let cell = sender as? InventoryTableViewCell{
vc.inventoryItem = cell.inventoryItem! //sets the inventory item accordingly, passing its reference along.
}else{
print("sender was something else")
}
}

}

func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int {
//This scrolls to correct section based on title of what was pressed.
return letterIndex.indexOf(title)!
}

func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
//This is smart and takes the first letter of known sections to create the Index Titles
return self.fetchedResultsController.sectionIndexTitles
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

if let sections = fetchedResultsController.sections {
let currentSection = sections[section]
return currentSection.numberOfObjects
}

return 0
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("InventoryTableCell", forIndexPath: indexPath) as! InventoryTableViewCell

let inventory = fetchedResultsController.objectAtIndexPath(indexPath) as! Inventory
cell.inventoryItem = inventory

cell.drawCell() //uses passed inventoryItem to draw it's self accordingly.

return cell

}

func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {

if let sections = fetchedResultsController.sections {
let currentSection = sections[section]
return currentSection.name
}

return nil
}

func numberOfSectionsInTableView(tableView: UITableView) -> Int {

if let sections = fetchedResultsController.sections {
return sections.count
}

return 0
}

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//dispatch_async(dispatch_get_main_queue()) {
//[unowned self] in
print("didSelectRowAtIndexPath")//does not recognize first time pressed item for some reason?
let selectedCell = self.tableView(tableView, cellForRowAtIndexPath: indexPath) as? InventoryTableViewCell
self.performSegueWithIdentifier("inventoryInfoSegue", sender: selectedCell)
//}

}


@IBAction func BarcodeScanBarItemAction(sender: UIBarButtonItem) {
print("test of baritem")
}
@IBAction func SetStoreBarItemAction(sender: UIBarButtonItem) {
print("change store interface")
}

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
print("text is changing")
}

func searchBarCancelButtonClicked(searchBar: UISearchBar) {
print("ended by cancel")
searchBar.text = ""
searchBar.resignFirstResponder()
}

func searchBarSearchButtonClicked(searchBar: UISearchBar) {
print("ended by search")
searchBar.resignFirstResponder()
}

func searchBarTextDidEndEditing(searchBar: UISearchBar) {
print("ended by end editing")
searchBar.resignFirstResponder()
}

@IBAction func unwindBackToInventory(segue: UIStoryboardSegue) {
print("unwind attempt")

let barcode = (segue.sourceViewController as? ScannerViewController)?.barcode
searchBar.text = barcode!

print("barcode="+barcode!)

inventoryTable.reloadData()//reload the data to be safe.

}

}

//Extention to INT to create random number in range.
extension Int
{
static func random(range: Range<Int> ) -> Int
{
var offset = 0

if range.startIndex < 0 // allow negative ranges
{
offset = abs(range.startIndex)
}

let mini = UInt32(range.startIndex + offset)
let maxi = UInt32(range.endIndex + offset)

return Int(mini + arc4random_uniform(maxi - mini)) - offset
}
}

注意:

我还清除了电话数据库,以防万一它是旧数据库,方法是删除应用程序(按住直到它摆动并删除)。

最佳答案

当您的核心数据持久存储存储在 SQLite 中时(我在这里假设,否则其他答案已经有效)您不能使用计算属性或 transient 属性。

但是,您可以更改您的数据模型,以便将该条形码的最后一位存储在它自己的属性中(称为非规范化),然后根据该新属性进行排序。这是正确的答案。

您还可以在完成提取后进行二次排序。然而,这意味着您在 NSFetchedResultsController 之外持有一个已排序的数组,然后您需要在从 NSFetchedResultsController 接收委托(delegate)回调时维护该数组的顺序。这是第二好的答案。

如果可以更改数据模型,则添加排序属性。否则你的 View Controller 代码会因为第二种而变得更复杂。

关于ios - NSFetchedResultsController 字符串最后一个字符的排序描述符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36527093/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com