Afhandeling iPhone Core Data “Productie”

Ik heb in de voorbeeldcode van Apple verwijzingen gezien naar hoe je met Core Data-fouten moet omgaan. D.w.z.:

NSError *error = nil;
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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
 */
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

Maar nooit voorbeelden van hoe je het moetimplementeren.

Heeft iemand (of kan mij in de richting van) een echte “productie”-code die de bovenstaande methode illustreert.

Bij voorbaat dank,
Matt


Antwoord 1, autoriteit 100%

Niemand zal u productiecode laten zien, omdat dit 100% afhangt van uw toepassing en waar de fout optreedt.

Persoonlijk heb ik daar een assert-statement geplaatst omdat deze fout zich in 99,9% van de tijd tijdens de ontwikkeling zal voordoen en als je hem daar oplost, is het hoogstonwaarschijnlijk dat je hem in productie zult zien.

Na de bewering zou ik de gebruiker een waarschuwing geven, hem laten weten dat er een onherstelbare fout is opgetreden en dat de toepassing wordt afgesloten. Je kunt daar ook een flaptekst plaatsen met het verzoek contact op te nemen met de ontwikkelaar, zodat je dit hopelijk kunt volgen.

Daarna zou ik de abort() daarin laten staan ​​omdat het de app zal “crashen” en een stacktracering zal genereren die je hopelijk later kunt gebruiken om het probleem op te sporen.


Antwoord 2, autoriteit 100%

Dit is een generieke methode die ik heb bedacht om validatiefouten op de iPhone af te handelen en weer te geven. Maar Marcus heeft gelijk: je zou de berichten waarschijnlijk willen aanpassen om ze gebruiksvriendelijker te maken. Maar dit geeft je in ieder geval een startpunt om te zien welk veld niet is gevalideerd en waarom.

- (void)displayValidationError:(NSError *)anError {
    if (anError && [[anError domain] isEqualToString:@"NSCocoaErrorDomain"]) {
        NSArray *errors = nil;
        // multiple errors?
        if ([anError code] == NSValidationMultipleErrorsError) {
            errors = [[anError userInfo] objectForKey:NSDetailedErrorsKey];
        } else {
            errors = [NSArray arrayWithObject:anError];
        }
        if (errors && [errors count] > 0) {
            NSString *messages = @"Reason(s):\n";
            for (NSError * error in errors) {
                NSString *entityName = [[[[error userInfo] objectForKey:@"NSValidationErrorObject"] entity] name];
                NSString *attributeName = [[error userInfo] objectForKey:@"NSValidationErrorKey"];
                NSString *msg;
                switch ([error code]) {
                    case NSManagedObjectValidationError:
                        msg = @"Generic validation error.";
                        break;
                    case NSValidationMissingMandatoryPropertyError:
                        msg = [NSString stringWithFormat:@"The attribute '%@' mustn't be empty.", attributeName];
                        break;
                    case NSValidationRelationshipLacksMinimumCountError:  
                        msg = [NSString stringWithFormat:@"The relationship '%@' doesn't have enough entries.", attributeName];
                        break;
                    case NSValidationRelationshipExceedsMaximumCountError:
                        msg = [NSString stringWithFormat:@"The relationship '%@' has too many entries.", attributeName];
                        break;
                    case NSValidationRelationshipDeniedDeleteError:
                        msg = [NSString stringWithFormat:@"To delete, the relationship '%@' must be empty.", attributeName];
                        break;
                    case NSValidationNumberTooLargeError:                 
                        msg = [NSString stringWithFormat:@"The number of the attribute '%@' is too large.", attributeName];
                        break;
                    case NSValidationNumberTooSmallError:                 
                        msg = [NSString stringWithFormat:@"The number of the attribute '%@' is too small.", attributeName];
                        break;
                    case NSValidationDateTooLateError:                    
                        msg = [NSString stringWithFormat:@"The date of the attribute '%@' is too late.", attributeName];
                        break;
                    case NSValidationDateTooSoonError:                    
                        msg = [NSString stringWithFormat:@"The date of the attribute '%@' is too soon.", attributeName];
                        break;
                    case NSValidationInvalidDateError:                    
                        msg = [NSString stringWithFormat:@"The date of the attribute '%@' is invalid.", attributeName];
                        break;
                    case NSValidationStringTooLongError:      
                        msg = [NSString stringWithFormat:@"The text of the attribute '%@' is too long.", attributeName];
                        break;
                    case NSValidationStringTooShortError:                 
                        msg = [NSString stringWithFormat:@"The text of the attribute '%@' is too short.", attributeName];
                        break;
                    case NSValidationStringPatternMatchingError:          
                        msg = [NSString stringWithFormat:@"The text of the attribute '%@' doesn't match the required pattern.", attributeName];
                        break;
                    default:
                        msg = [NSString stringWithFormat:@"Unknown error (code %i).", [error code]];
                        break;
                }
                messages = [messages stringByAppendingFormat:@"%@%@%@\n", (entityName?:@""),(entityName?@": ":@""),msg];
            }
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Validation Error" 
                                                            message:messages
                                                           delegate:nil 
                                                  cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
            [alert show];
            [alert release];
        }
    }
}

Genieten.


3, Autoriteit 18%

Ik ben verrast, niemand hier daadwerkelijk de fout afhandelt zoals het is bedoeld om te worden afgehandeld. Als u naar de documentatie kijkt, ziet u.

Typische redenen voor een fout hieronder: * Het apparaat is uit
van ruimte. * De aanhoudende winkel is niet toegankelijk, vanwege
Machtigingen of gegevensbescherming wanneer het apparaat is vergrendeld. * De
winkel kon niet worden gemigreerd naar de huidige modelversie. * De
Oudermap bestaat niet, kan niet worden gecreëerd of niet toegewijd
schrijven.

Dus als ik een fout vind bij het instellen van de Core Data Stack, swap ik de wortelviewController van UIWINDOW en toon UI die de gebruiker duidelijk vertelt dat hun apparaat mogelijk vol is, of hun beveiligingsinstellingen zijn te hoog voor deze app om te functioneren . Ik geef ze ook een ‘Probeer opnieuw’, zodat ze kunnen proberen het probleem op te lossen voordat de kerngegevensstapel opnieuw wordt geprobeerd.

Bijvoorbeeld de gebruiker kan een opslagruimte vrijmaken, terugkeren naar mijn app en druk op de knop PROBEREN opnieuw.

beweert? Echt? Te veel ontwikkelaars in de kamer!

Ik ben ook verrast door het aantal online tutorials dat niet vermeldt hoe een opslagbewerking om deze redenen kan mislukken. U moet dus ervoor zorgen dat een opslagevenement overal in uw app kan falen, omdat het apparaat slechts deze minuut vol werd met uw apps opslaan opslaan opslaan.


Antwoord 4, autoriteit 9%

Ik heb een Swift-versie gemaakt van het nuttige antwoord van @JohannesFahrenkrug, wat nuttig kan zijn:

public func displayValidationError(anError:NSError?) -> String {
    if anError != nil && anError!.domain.compare("NSCocoaErrorDomain") == .OrderedSame {
        var messages:String = "Reason(s):\n"
        var errors = [AnyObject]()
        if (anError!.code == NSValidationMultipleErrorsError) {
            errors = anError!.userInfo[NSDetailedErrorsKey] as! [AnyObject]
        } else {
            errors = [AnyObject]()
            errors.append(anError!)
        }
        if (errors.count > 0) {
            for error in errors {
                if (error as? NSError)!.userInfo.keys.contains("conflictList") {
                    messages =  messages.stringByAppendingString("Generic merge conflict. see details : \(error)")
                }
                else
                {
                    let entityName = "\(((error as? NSError)!.userInfo["NSValidationErrorObject"] as! NSManagedObject).entity.name)"
                    let attributeName = "\((error as? NSError)!.userInfo["NSValidationErrorKey"])"
                    var msg = ""
                    switch (error.code) {
                    case NSManagedObjectValidationError:
                        msg = "Generic validation error.";
                        break;
                    case NSValidationMissingMandatoryPropertyError:
                        msg = String(format:"The attribute '%@' mustn't be empty.", attributeName)
                        break;
                    case NSValidationRelationshipLacksMinimumCountError:
                        msg = String(format:"The relationship '%@' doesn't have enough entries.", attributeName)
                        break;
                    case NSValidationRelationshipExceedsMaximumCountError:
                        msg = String(format:"The relationship '%@' has too many entries.", attributeName)
                        break;
                    case NSValidationRelationshipDeniedDeleteError:
                        msg = String(format:"To delete, the relationship '%@' must be empty.", attributeName)
                        break;
                    case NSValidationNumberTooLargeError:
                        msg = String(format:"The number of the attribute '%@' is too large.", attributeName)
                        break;
                    case NSValidationNumberTooSmallError:
                        msg = String(format:"The number of the attribute '%@' is too small.", attributeName)
                        break;
                    case NSValidationDateTooLateError:
                        msg = String(format:"The date of the attribute '%@' is too late.", attributeName)
                        break;
                    case NSValidationDateTooSoonError:
                        msg = String(format:"The date of the attribute '%@' is too soon.", attributeName)
                        break;
                    case NSValidationInvalidDateError:
                        msg = String(format:"The date of the attribute '%@' is invalid.", attributeName)
                        break;
                    case NSValidationStringTooLongError:
                        msg = String(format:"The text of the attribute '%@' is too long.", attributeName)
                        break;
                    case NSValidationStringTooShortError:
                        msg = String(format:"The text of the attribute '%@' is too short.", attributeName)
                        break;
                    case NSValidationStringPatternMatchingError:
                        msg = String(format:"The text of the attribute '%@' doesn't match the required pattern.", attributeName)
                        break;
                    default:
                        msg = String(format:"Unknown error (code %i).", error.code) as String
                        break;
                    }
                    messages = messages.stringByAppendingString("\(entityName).\(attributeName):\(msg)\n")
                }
            }
        }
        return messages
    }
    return "no error"
}`

Other episodes