दिलचस्प पोस्ट
एंड्रॉइड बैकबूटन व्यवहार को ओवरराइड केवल फोनजीप के साथ पहला पेज पर काम करता है टाइमर के साथ विंडोज सर्विस कार्यात्मक प्रोग्रामिंग शैली में सबसे अच्छा काम क्या है? प्रमुख नामों को जानने के बिना JSON ऑब्जेक्ट के तत्वों तक पहुंच '__asm' और '__asm__' के बीच अंतर क्या है? स्थानीय चर के लिए WPF बाध्यकारी सी # में JSON फ़ॉर्मेटर? रनटाइम पर एक प्रकार का डिफ़ॉल्ट मान स्थानीय मेवेन प्रॉक्सी रिपॉजिटरी (नेक्सस) का उपयोग करने के लिए मैं एसबीटी कैसे प्राप्त करूं? (पदावनत) टुकड़े पर ओपेशन्स आईटम चयनित नहीं किया जा रहा है आर में फ्लोटिंग पॉइंट इश्यू? क्या मैं NSLayoutConstraint के लिए गुणक संपत्ति बदल सकता हूँ? पेजिंग को लागू करने के लिए प्रभावी तरीका क्या पायथन में पैकेज / मॉड्यूल प्रबंधन प्रणाली है? 2038 से परे PHP में तिथियां एक्सेस करना

CoreData रिकॉर्ड के पुन: आदेश को कैसे कार्यान्वित करें?

मैं अपने iPhone ऐप के लिए CoreData का उपयोग कर रहा हूं, लेकिन कोरडाटा आपको रिकॉर्ड्स को पुन: क्रमित करने की अनुमति देने का एक स्वचालित तरीका प्रदान नहीं करता है। मैं ऑर्डर की जानकारी को स्टोर करने के लिए एक और कॉलम का उपयोग करने के बारे में सोचा था, लेकिन इंडेक्स ऑर्डर करने के लिए संगत संख्याओं का उपयोग करने में समस्या है अगर मैं बहुत से डेटा के साथ काम कर रहा हूं, तो एक रिकार्ड की पुनर्रांडण करना संभावित रूप से ऑर्डरिंग जानकारी पर बहुत सारे रिकॉर्ड अपडेट करना शामिल है (यह एक सरणी तत्व के क्रम को बदलने जैसा है)

एक कुशल आदेश योजना को लागू करने का सबसे अच्छा तरीका क्या है?

Solutions Collecting From Web of "CoreData रिकॉर्ड के पुन: आदेश को कैसे कार्यान्वित करें?"

FetchedResultsController और इसका प्रतिनिधि प्रयोक्ता चालित मॉडल परिवर्तनों के लिए उपयोग करने के लिए नहीं हैं ऐप्पल संदर्भ डॉक देखें उपयोगकर्ता द्वारा संचालित अद्यतन भाग को देखें तो अगर आप कुछ जादुई, एक-लाइन तरीके की तलाश करते हैं, तो ऐसा नहीं है, दुख की बात है।

आपको क्या करना है इस पद्धति में अद्यतन करना है:

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { userDrivenDataModelChange = YES; ...[UPDATE THE MODEL then SAVE CONTEXT]... userDrivenDataModelChange = NO; } 

और कुछ भी करने के लिए नोटिफिकेशन को भी रोकते हैं, क्योंकि उपयोगकर्ता द्वारा परिवर्तन पहले से ही किए गए हैं:

 - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { if (userDrivenDataModelChange) return; ... } - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { if (userDrivenDataModelChange) return; ... } - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { if (userDrivenDataModelChange) return; ... } 

मैंने अभी तक अपने टू-डू ऐप (क्विक) में इसे लागू किया है और यह ठीक काम करता है।

यहां एक त्वरित उदाहरण है, जिसने नतीजे वाले परिणामों को एक NSMutableArray में डंप करने का तरीका दिखाया है जो कि आप सेल के चारों ओर ले जाने के लिए उपयोग करते हैं। उसके बाद आप बस orderInTable नामक इकाई पर एक विशेषता को अपडेट orderInTable और फिर प्रबंधित वस्तु संदर्भ को सहेजते हैं।

इस तरह, मैन्युअल रूप से इंडेक्सेस को बदलने के बारे में आपको चिंता करने की ज़रूरत नहीं है और इसके बदले आप NSMutableArray को आपके लिए हैंडल करते हैं।

एक BOOL बनाएँ जिसे आप अस्थायी रूप से NSFetchedResultsControllerDelegate बायपास करने के लिए उपयोग कर सकते हैं

 @interface PlaylistViewController () { BOOL changingPlaylistOrder; } @end 

टेबल दृश्य प्रतिनिधि विधि:

 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { // Refer to https://developer.apple.com/library/ios/documentation/CoreData/Reference/NSFetchedResultsControllerDelegate_Protocol/Reference/Reference.html#//apple_ref/doc/uid/TP40008228-CH1-SW14 // Bypass the delegates temporarily changingPlaylistOrder = YES; // Get a handle to the playlist we're moving NSMutableArray *sortedPlaylists = [NSMutableArray arrayWithArray:[self.fetchedResultsController fetchedObjects]]; // Get a handle to the call we're moving Playlist *playlistWeAreMoving = [sortedPlaylists objectAtIndex:sourceIndexPath.row]; // Remove the call from it's current position [sortedPlaylists removeObjectAtIndex:sourceIndexPath.row]; // Insert it at it's new position [sortedPlaylists insertObject:playlistWeAreMoving atIndex:destinationIndexPath.row]; // Update the order of them all according to their index in the mutable array [sortedPlaylists enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { Playlist *zePlaylist = (Playlist *)obj; zePlaylist.orderInTable = [NSNumber numberWithInt:idx]; }]; // Save the managed object context [commonContext save]; // Allow the delegates to work now changingPlaylistOrder = NO; } 

आपके प्रतिनिधियों को अब ऐसा कुछ दिखाई देगा:

 - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { if (changingPlaylistOrder) return; switch(type) { case NSFetchedResultsChangeMove: [self configureCell:(PlaylistCell *)[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; break; } } - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { if (changingPlaylistOrder) return; [self.tableView reloadData]; } 

देर से उत्तर: शायद आप स्ट्रिंग के रूप में सॉर्ट कुंजी को स्टोर कर सकते हैं। दो मौजूदा पंक्तियों के बीच एक रिकॉर्ड डालने के लिए एक स्ट्रिंग के लिए एक अतिरिक्त वर्ण जोड़ कर, उदाहरण के लिए, "ए" और "बी" पंक्तियों के बीच "AM" डालना कोई पुनर्रांडिंग आवश्यक नहीं है एक समान विचार एक फ्लोटिंग प्वाइंट नंबर या 4-बाइट पूर्णांक पर कुछ साधारण बिट अंकगणित का उपयोग करके पूरा किया जा सकता है: सन्निकट पंक्ति के साथ एक पंक्ति डालें जो आसन्न पंक्तियों के बीच का आधा रास्ता है।

जहां तक ​​स्ट्रिंग बहुत लंबी है, रोगाणु मामलों में यह वृद्धि बहुत छोटी है, या फिर इंटर्न में कोई और जगह नहीं है, लेकिन फिर आप इकाई को पुनः शुरू कर सकते हैं और एक नई शुरुआत कर सकते हैं। एक दुर्लभ अवसर पर अपने सभी रिकॉर्ड के माध्यम से स्कैन और अपडेट करना प्रत्येक प्रयोक्ता को दोबारा गलती करने से बेहतर होता है।

उदाहरण के लिए, int32 पर विचार करें प्रारंभिक आदेश के रूप में उच्च 3 बाइट्स का उपयोग करके आप लगभग 17 मिलियन पंक्तियों को किसी भी दो पंक्तियों के बीच 256 पंक्तियों तक डालने की क्षमता प्रदान कर सकते हैं। 2 बाइट्स पुन: स्कैन करने से पहले किसी भी दो पंक्तियों के बीच 65000 पंक्तियों को सम्मिलित करने की अनुमति देती है।

यहाँ छद्म कोड है जिसमें मुझे दो बाइट वेतन वृद्धि और 2 बाइट्स डालने के लिए ध्यान दिया गया है:

 AppendRow:item item.sortKey = tail.sortKey + 0x10000 InsertRow:item betweenRow:a andNextRow:b item.sortKey = a.sortKey + (b.sortKey - a.sortKey) >> 1 

आम तौर पर आप अपेंडरो को बुलाते हुए पंक्तियों में 0x10000, 0x20000, 0x30000, आदि के साथ पंक्तियों में उत्पन्न होंगे। कभी-कभी आपको पहले और दूसरे के बीच में डालें, फिर से 0x180000 के एक प्रकार की कि के परिणामस्वरूप कहें।

मैंने @ वंडू / @ डीके के दृष्टिकोण को दोहरे मूल्यों के साथ लागू किया है I

आप github पर UIOrderedTableView पा सकते हैं।

इसे कांटा करने के लिए स्वतंत्र महसूस 🙂

मै मैथ गैलाघर के ब्लॉग से इस विधि से अपनाया (मूल लिंक नहीं मिल सकता है) यह आपके पास लाखों रिकॉर्ड होने का सबसे अच्छा समाधान नहीं हो सकता है, लेकिन उपयोगकर्ता द्वारा रिकॉर्डेड रिकॉर्ड को पूरा करने तक बचत को स्थगित कर दिया जाएगा।

 - (void)moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath sortProperty:(NSString*)sortProperty { NSMutableArray *allFRCObjects = [[self.frc fetchedObjects] mutableCopy]; // Grab the item we're moving. NSManagedObject *sourceObject = [self.frc objectAtIndexPath:sourceIndexPath]; // Remove the object we're moving from the array. [allFRCObjects removeObject:sourceObject]; // Now re-insert it at the destination. [allFRCObjects insertObject:sourceObject atIndex:[destinationIndexPath row]]; // All of the objects are now in their correct order. Update each // object's displayOrder field by iterating through the array. int i = 0; for (NSManagedObject *mo in allFRCObjects) { [mo setValue:[NSNumber numberWithInt:i++] forKey:sortProperty]; } //DO NOT SAVE THE MANAGED OBJECT CONTEXT YET } - (void)setEditing:(BOOL)editing { [super setEditing:editing]; if(!editing) [self.managedObjectContext save:nil]; } 

असल में, बहुत आसान तरीका है, एक ऑर्डरिंग कॉलम के रूप में "डबल" प्रकार का उपयोग करें।

फिर जब भी आप फिर से ऑर्डर करते हैं, तो आपको केवल क्रमबद्ध आइटम के लिए ऑर्डर विशेषता के मूल्य को रीसेट करने की आवश्यकता होती है:

 reorderedItem.orderValue = previousElement.OrderValue + (next.orderValue - previousElement.OrderValue) / 2.0; 

मैं अंत में संपादक को मोड में FetchController पर छोड़ दिया है क्योंकि मुझे अपने टेबल कोशिकाओं को पुन: व्यवस्थित करने की आवश्यकता है I मैं इसे काम करने का एक उदाहरण देखना चाहता हूं इसके बदले मैं एक म्यूटिवैर्रैज़ तालिका के वर्तमान दृश्य होने के साथ रखता था, और कोरडाटा ऑर्डर इटैम को लगातार रखते हुए रखते हुए।

 NSUInteger fromRow = [fromIndexPath row]; NSUInteger toRow = [toIndexPath row]; if (fromRow != toRow) { // array up to date id object = [[eventsArray objectAtIndex:fromRow] retain]; [eventsArray removeObjectAtIndex:fromRow]; [eventsArray insertObject:object atIndex:toRow]; [object release]; NSFetchRequest *fetchRequestFrom = [[NSFetchRequest alloc] init]; NSEntityDescription *entityFrom = [NSEntityDescription entityForName:@"Lister" inManagedObjectContext:managedObjectContext]; [fetchRequestFrom setEntity:entityFrom]; NSPredicate *predicate; if (fromRow < toRow) predicate = [NSPredicate predicateWithFormat:@"itemOrder >= %d AND itemOrder <= %d", fromRow, toRow]; else predicate = [NSPredicate predicateWithFormat:@"itemOrder <= %d AND itemOrder >= %d", fromRow, toRow]; [fetchRequestFrom setPredicate:predicate]; NSError *error; NSArray *fetchedObjectsFrom = [managedObjectContext executeFetchRequest:fetchRequestFrom error:&error]; [fetchRequestFrom release]; if (fetchedObjectsFrom != nil) { for ( Lister* lister in fetchedObjectsFrom ) { if ([[lister itemOrder] integerValue] == fromRow) { // the item that moved NSNumber *orderNumber = [[NSNumber alloc] initWithInteger:toRow]; [lister setItemOrder:orderNumber]; [orderNumber release]; } else { NSInteger orderNewInt; if (fromRow < toRow) { orderNewInt = [[lister itemOrder] integerValue] -1; } else { orderNewInt = [[lister itemOrder] integerValue] +1; } NSNumber *orderNumber = [[NSNumber alloc] initWithInteger:orderNewInt]; [lister setItemOrder:orderNumber]; [orderNumber release]; } } NSError *error; if (![managedObjectContext save:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); // Fail } } } 

अगर किसी के पास फ़ेच कंट्रोलर का उपयोग करते हुए कोई समाधान है, तो उसे पोस्ट करें।

तो इस समस्या पर कुछ समय बिताया …!

ऊपर दिए गए उत्तर महान इमारत के ब्लॉक हैं और उनके बिना मैं खो गया होता, लेकिन जैसा कि अन्य उत्तरदाताओं के साथ मैंने पाया कि वे केवल आंशिक रूप से काम करते हैं यदि आप उन्हें लागू करते हैं तो आपको पता चल जाएगा कि वे एक बार या दो बार काम करते हैं, फिर त्रुटि होती हैं, या आप जितनी भी हो वहां डेटा खो देते हैं। नीचे दिए गए उत्तर सही से बहुत दूर हैं – यह देर रात, परीक्षण और त्रुटि की बहुत सारी परिणाम है।

इन तरीकों से कुछ मुद्दे हैं:

  1. NSMutableArray से जुड़े NSFetchedResultsController गारंटी नहीं देता कि संदर्भ अपडेट हो जाएगा, इसलिए आप देख सकते हैं कि यह कभी-कभी काम करता है, लेकिन अन्य नहीं।

  2. प्रतिलिपि फिर ऑप्स ऑप्स के लिए दृष्टिकोण हटाना भी भविष्यवाणी करने के लिए मुश्किल व्यवहार है। मैंने किसी वस्तु को संदर्भित करने में अप्रत्याशित व्यवहार के लिए संदर्भ कहीं और पाया जो संदर्भ में हटा दिया गया था।

  3. यदि आप वस्तु सूचकांक पंक्ति का उपयोग करते हैं और अनुभाग हैं, तो यह ठीक से व्यवहार नहीं करेगा। ऊपर दिए गए कुछ कोड का उपयोग केवल .ro संपत्ति का होता है और दुर्भाग्य से यह एक या अधिक में एक से अधिक पंक्ति का उल्लेख कर सकता है

  4. NSFetchedResults Delegate = nil का उपयोग करना, साधारण अनुप्रयोगों के लिए ठीक है, परन्तु ध्यान रखें कि आप उस प्रतिनिधि को उस परिवर्तन पर कब्जा करने के लिए उपयोग करना चाहते हैं जिसे एक डेटाबेस में दोहराया जाएगा और आप देख सकते हैं कि यह ठीक से काम नहीं करेगा।

  5. कोर डेटा वास्तव में सॉर्टिंग और ऑर्डर करने का समर्थन नहीं करता है कि एक उचित SQL डेटाबेस करता है ऊपर लूप समाधान के लिए अच्छा है, लेकिन वास्तव में डेटा क्रम का एक उचित तरीका होना चाहिए – IOS8? – इसलिए आपको उम्मीद है कि आपका डेटा पूरे स्थान पर होगा।

इन पदों के जवाब में लोगों ने जो मुद्दों को पोस्ट किया है, उनमें से बहुत से मुद्दों का संबंध है।

मुझे 'आंशिक रूप से' काम करने के लिए वर्गों के साथ एक साधारण टेबल ऐप मिल गया है – मैं अब भी असम्बद्ध यूआई व्यवहारों पर काम कर रहा हूं, लेकिन मेरा मानना ​​है कि मुझे इसके नीचे मिला है …

 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath 

यह सामान्य प्रतिनिधि है

 { userDrivenDataModelChange = YES; 

यदि () रिटर्न संरचनाओं के साथ ऊपर वर्णित के रूप में सेमाफोर तंत्र का उपयोग करता है

 NSInteger sourceRow = sourceIndexPath.row; NSInteger sourceSection = sourceIndexPath.section; NSInteger destinationRow = destinationIndexPath.row; NSInteger destinationSection = destinationIndexPath.section; 

इन सभी को कोड में उपयोग नहीं किया जाता है, लेकिन उन्हें डीबगिंग के लिए उपयोगी है

 NSError *error = nil; NSIndexPath *destinationDummy; int i = 0; 

चर का अंतिम इनिशियलाइजेशन

 destinationDummy = [NSIndexPath indexPathForRow:0 inSection:destinationSection] ; // there should always be a row zero in every section - although it's not shown 

मैं प्रत्येक खंड में एक पंक्ति 0 का उपयोग करता हूं जो छुपा हुआ है, यह अनुभाग नाम को संग्रहीत करता है। यह अनुभाग को दृश्यमान होने की अनुमति देता है, भले ही इसमें कोई 'लाइव रिकॉर्ड न हो। मैं अनुभाग नाम प्राप्त करने के लिए पंक्ति 0 का उपयोग करता हूं। यहां कोड थोड़ा गड़बड़ है, लेकिन यह नौकरी करता है।

 NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext]; NSManagedObject *currentObject = [self.fetchedResultsController objectAtIndexPath:sourceIndexPath]; NSManagedObject *targetObject = [self.fetchedResultsController objectAtIndexPath:destinationDummy]; 

संदर्भ और स्रोत और गंतव्य वस्तुएं प्राप्त करें

यह कोड तब एक नया ऑब्जेक्ट बनाता है जो स्रोत से डेटा लेता है, और गंतव्य से अनुभाग।

 // set up a new object to be a copy of the old one NSManagedObject *newObject = [NSEntityDescription insertNewObjectForEntityForName:@"List" inManagedObjectContext:context]; NSString *destinationSectionText = [[targetObject valueForKey:@"section"] description]; [newObject setValue:destinationSectionText forKeyPath:@"section"]; [newObject setValue: [NSNumber numberWithInt:9999999] forKey:@"rowIndex"]; NSString *currentItem = [[currentObject valueForKey:@"item"] description]; [newObject setValue:currentItem forKeyPath:@"item"]; NSNumber *currentQuantity =[currentObject valueForKey:@"quantity"] ; [newObject setValue: currentQuantity forKey:@"rowIndex"]; 

अब एक नया ऑब्जेक्ट बनाइए और प्रोजेक्ट को बचाएं – यह चाल की कार्रवाई को धोखा दे रहा है – हो सकता है कि आपको उस जगह पर नया रिकार्ड न मिले जो इसे हटा दिया गया था – लेकिन कम से कम यह सही अनुभाग में होगा।

 // create a copy of the object for the new location [context insertObject:newObject]; [context deleteObject:currentObject]; if (![context save:&error]) { // Replace this implementation with code to handle the error appropriately. // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } 

अब ऊपर बताए अनुसार लूप अपडेट के लिए करें। ध्यान दें कि संदर्भ मेरे द्वारा करने से पहले बचाया जाता है – पता नहीं क्यों इसकी आवश्यकता है, लेकिन यह ठीक से काम नहीं कर रहा जब यह नहीं था!

 i = 0; for (NSManagedObject *mo in [self.fetchedResultsController fetchedObjects] ) { [mo setValue:[NSNumber numberWithInt:i++] forKey:@"rowIndex"]; } if (![context save:&error]) { // Replace this implementation with code to handle the error appropriately. // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } 

सिक्वॉर वापस सेट करें और तालिका अपडेट करें

 userDrivenDataModelChange = NO; [tableView reloadData]; 

}

यह है कि मैं क्या कर रहा हूं जो काम करने लगता है प्रत्येक इकाई के लिए मेरे पास एक createDate है जिसका उपयोग तालिका बनाते समय किया जाता है। यह एक अद्वितीय कुंजी के रूप में भी कार्य करता है इसलिए मैंने जो कदम उठाया है, वह स्रोत और गंतव्य तिथियां स्वैप करता है।

मैं उम्मीद करता हूं कि तालिका सहेजे जाने के बाद ठीक से आदेश दिया जाना चाहिए, लेकिन क्या होता है, दो कोशिकाओं को सिर्फ एक-दूसरे के ऊपर रखना था इसलिए मैं डेटा पुनः लोड करता हूं और ऑर्डर ठीक है I स्क्रैच से ऐप को शुरू करने से रिकॉर्ड को उचित क्रम में दिखाया गया है।

यह निश्चित नहीं है कि यह सामान्य समाधान या सही भी है, लेकिन अब तक यह काम करने लगता है

 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { HomeEntity* source_home = [self getHomeEntityAtIndexPath:sourceIndexPath]; HomeEntity* destination_home = [self getHomeEntityAtIndexPath:destinationIndexPath]; NSTimeInterval temp = destination_home.createDate; destination_home.createDate = source_home.createDate; source_home.createDate = temp; CoreDataStack * stack = [CoreDataStack defaultStack]; [stack saveContext]; [self.tableView reloadData]; } 

आईफ़ोन के लिए कोर डेटा ट्यूटोरियल पर एक नज़र डालने का प्रयास करें । अनुभागों में से एक में सॉर्टिंग के बारे में बात करते हैं (NSSortDescriptor का उपयोग करते हुए)

आपको उपयोगी होने के लिए कोर डेटा मूलभूत पृष्ठ भी मिल सकता है।