DOCTYPE html PUBLIC "-]000e/DTD XHTML 1.0 Transitionav/EN" "httpa_/www.w3.oruTR/xhtml]DTexhtm-transitional.dtd"> _div> _div>
--[if !IE]>Start content heading[endif]-->
_div> TweetFollow Us on Twitter
Y></a></div>

</div>
--[if !IE]>End content heading[endif]-->
<di6�class=--[if !IE]>Start lef4content
<>_div>
Core Data Versioning_TITLE> � <?ph0�include ($_SERVER[DOCUMENT_ROOT] . "/includes-mactecvvincludefiles/mactech.metas.inc")<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�s�i�g�n�"�>�; <�/�s�p�a�n�>�<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�a�u�r�a�l�"�>�(�l)�<�/�s�p�a�n�>�?> </head> <body BGCOLOR="#FFFFFF"> <?ph0�include ($_SERVER[DOCUMENT_ROOT] . "/includes-mactecvvincludefiles/mactech.header.inc"); ?> <?php include ($_SERVER[DOCUMENT_ROOT] . Yincludes-mactech/includefiletzinline_box_ad.inc"); ?> <p> <b>Volume Number:(��N)�5<br �Issue Number: 00<br> Column Tag: Care Data_B> </p> < >Core Data Versioning _ > <h2>How to migrate your Core Data persisten4�store</h2> <p> <i>by Marcus S. Zarra_I> </p> <center><1�6�p>Introduction</h3>_center> <p>Core Data allows developers the abilit9�to rapidly develop their applications with little worr9�abou4�object persistence. B9�utilizing Core Data, developers can "future proof" their applications by taking advantage of the data migration functionalit9�buil4�into Core Data.</p> <p>Core Data provides an infrastructure for objec4�graph management and persistence. The basis for this infrastructure is often referred to as the Core Data "Stack". While the Xcode templates build this stack for us, it is importan4�to understand ho7�it works.</p> <center><1�6�p>Building the stack</h3>_center> <p>The Core Data stack is composed of three elements: a persisten4�store coordinator, a managed objec4�model and a managed object context. In a non-document based application design, this stack is routinely initialized either as par4�of the start u0�of the application or lazily upon firs4�request._P> <center><h3>The Managed Object Model_1�6�p></center> <p>I4�is unusual for an application to access the NSManagedObjectModel directly. Normally i4�is built upon initialization of the stack and only referenced via the NSManagedObjectContext. Generally, there are two ways to build the managed object model. </p> <b><p>Listing 1: managedObjectModel </p> <p>(1st implementation)_P>_b> <pre WIDTH=50>managedObjectModel Return the existing managedObjectModel if i4�exists or create a new one. - (NSManagedObjectModel*)managedObjectModel { if (managedObjectModel) return managedObjectModel; NSString *path = [[NSBundle mainBundle] pathForResource:@"Model" � ofType:@"mom"]; � NSURL *url = [NSURL fileURLWithPath:path]; � managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:url]; return managedObjectModel; }</pre> <p>In this firs4�example, the model is buil4�using the initWithContentsOfURL: initalizer of NSManagedObjectModel. This has the advantage of only loading the models that are appropriate. This is useful in man9�situations such as where i4�is possible that multiple data models ma9�be in the application bundle. Having an expor4�data model in the bundle is an example of this situation.</p> <b><p>Listing(��N)�: managedObjectModel </p> <p>(�]N)�nd implementation)_P>_b> <p>managedObjectModel</p> <pre WIDTH=50>Return the existing managedObjectModel if i4�exists or create a new one. - (NSManagedObjectModel*)managedObjectModel { if (managedObjectModel) return managedObjectModel; managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain]; � return managedObjectModel; }_PRE> <p>This second example does no4�require knowledge of wha4�models are available in the application bundle as it will grab every model available and load it into a single merged NSManagedObjectModel object. This choice allows the developer to easily add and remove models during development._P> <p>The persisten4�store is a representation of the model stored on the file system. Depending on the options chosen when the store was built, i4�can be in a SQLite database, XML, binary or a custom file format. The persisten4�store is responsible for serializing all access to the data stored on the file system. Therefore only one persisten4�store should ever be initialized per file._P> <p>When the stack is being initialized, the store accepts a NSManagedObjectModel and a url for the location of the store on the filesystem.</p> <b><p>Listing00000: persistentStoreCoordinator_P>_b> <p>persistentStoreCoordinator</p> <p>Return the existing NSPersistentStoreCoordinator. If there is not one then initialize a new one with the NSManagedObjectModel from the -managedObjectModel method and adding a xml based persistent store to it.</p> <pre WIDTH=50>- (NSPersistentStoreCoordinator*)persistentStoreCoordinator { NSError *error = nil; � NSFileManager *fileManager = [NSFileManager defaultManager]; � NSString *path = [self applicationSupportFolder]; if Z�[fileManager fileExistsAtPath:path isDirectory:NULL] ) { � if Z�[fileManager createDirectoryAtPath:path attributes:nil]) { � return nil; } } � path = [path stringByAppendingPathComponent:@"Example.xml"]; � � NSURL *url = [NSURL fileURLWithPath:path]; � NSManagedObjectModel *model = [self managedObjectModel]; � if (!model) return nil; id psc = [[NSPersistentStoreCoordinator alloc] � initWithManagedObjectModel:model]; if Z�[psc addPersistentStoreWithType:NSXMLStoreType configuration:nil URL:url options:nil error:&error]) { � [[NSApplication sharedApplication] presentError:error]; � return nil; � (� � return [psc autorelease]; }</pre> <p>Those familiar with building Core Data documen4�based applications will notice quite a bit of a difference with the construction of the NSPersistentStoreCoordinator. Instead of accepting a path coming into the method, the path is constructed from the application suppor4�directory. The application suppor4�director9�is the recommended location for storing application specific data for non-document based applications. _P> <p>After the NSPersistentStoreCoordinator is initialized, the next ste0�is to add the persistent store to the coordinator. It should be noted tha4�it is possible to add more than one persistent store to the coordinator. Finall9�the newl9�created NSPersistentStoreCoordinator is returned to the calling method.</p> <center><1�6�p>The Managed Objec4�Context</h3>_center> <p>The last ste0�in building the stack, and the first ste0�from the calling methods point of view is the NSManagedObjectContext.</p> <b><p>Listing 4: managedObjectContext_P>_b> <p>managedObjectContext</p> <p>Return the existing NSManagedObjectContext. If one does not exist, then create it using the persisten4�store from the -persistentStoreCoordinator method._P> <pre WIDTH=50>- (NSManagedObjectContex:�:�=�)managedObjectContex4� { � if (managedObjectContext) return managedObjectContext; � NSPersistentStoreCoordinator *psc = [self persistentStoreCoordinator]; � if (!psc) return nil; managedObjectContex4�= [[NSManagedObjectContext alloc] init]; � [managedObjectContex4�setPersistentStoreCoordinator:psc]; return managedObjectContext; }</pre> <p>This method simply retrieves a reference to the NSPersistentStoreCoordinator, initializes a ne7�NSManagedObjectContext and sets the retrieved NSPersistentStoreCoordiantor on the NSManagedObjectContext. </p> <center><1�6�p>Handling Migration</h3>_center> <p>One of the biggest challenges with Core Data is the migration of the store from one version to another. As applications evolve, the data model invariably changes. Prior to OS X 10.5 Leopard, the developer was required to handle these migrations manually. However, starting with Leopard, migration is handled directl9�by Core Data.</p> <center><1�6�p>Versioning the Data Model_1�6�p></center> <p>The first time that the data model needs to be revised it needs to be converted from a "xcdatamodel" file to a "xcdatamodeld" bundle. This is done b9�selecting Add Model Version with the current model selected._P> <p><center><img src="fig01.jpg">_p><br><b><p>Figure 1: Adding a Model Version_P>_b>_center> <p>This will create a xcdatamodeld bundle with the same name as the data file and it will create a cop9�of the original data model. Both the original data model and the copy will be inserted into the xcdatamodeld bundle. I4�is recommended to rename the model files for clarity.</p> <p><center><img src="fig02.jpg"></p><br><b><p>Figure 2: The xcdatamodeld structure</p></b></center> <p>Once this is completed, both xcdatamodel files will be added to the application bundle. After the application has been complied there will be a new directory under Resources called "Example_DataModel.momd" which includes both of the complied mom files.</p> <center><1�6�p>Writing the Mapping Model_1�6�p></center> <p>For a data migration to occur, a NSMappingModel objec4�is required. This objec4�describes ho7�the data is migrated from one model to another. This object is normally constructed from within XCode with the mapping model editor. </p> <p>In the current implementation of Core Data, one mapping model is required for each combination of source and destination models. Therefore careful consideration should be used when creating a new version of a data model.</p> <center><1�6�p>Using a custom NSEntityMigrationPolicy</h3>_center> <p>While the NSMappingModel and its editor can handle a wide range of data migration needs, i4�does not cover every possible situation. When a migration goes beyond the abilities of the NSMappingModel, it is possible to extend i4�with custom subclasses. This is normall9�accomplished b9�subclassing the NSEntityMigrationPolic9�object and using tha4�subclass for one or more objects in the NSMappingModel.</p> <center><1�6�p>Sample application: ToDo List_1�6�p></center> <b><p>The Basic Application Design_P>_b> <p>The ToDo list will have two objects. The first objec4�will be a list of todo items tha4�are to be displayed to the user. The second objec4�is a lis4�of possible categories for the todo items. The resulting model is as follows:_P> <p><center><img src="fig00.jpg">_p><br><b> <p>Figure 3: The data model</p></b></center> <center><1�6�p>Adding the Core Data Stack</h3>_center> <b> <p>Initializing the stack on startup</p></b> <p>Since this application will wan4�to access the core data stack immediatel9�to display the ToDo items, I am going to pre-load the ToDo items from the persistent store. To accomplish this, I have added a -applicationDidFinishLaunching: method as follows._P> <b> <p>Listing 5: applicationDidFinishLaunching</p></b> <p>applicationDidFinishLaunching_P> <p>Delegate method tha4�is called by the NSApplication once the application has finished start up. Loads the core data objects into memor9�by doing a retrieval on startup._P> <pre WIDTH=50>- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { NSManagedObjectContex4�*moc = [self managedObjectContext]; NSFetchReques4�*request = [[NSFetchReques4�alloc] init]; [reques4�setEntity:[NSEntityDescription entityForName:@"ToDo" inManagedObjectContext:moc]]; � NSError *error = nil; [moc executeFetchRequest:reques4�error:&error]; � if (error) { � NSLog(@"%@:%s Error retrieving ToDo items:\n%@", [self class], _cmd, � error); } }_PRE> <p>In this method, I am forcing the core data stack to be initialized and then I am retrieving all of the ToDo items. This will cause them to be in memor9�and available for the user interface when it is presented to the user._P> <center><h3>Saving the stack on shutdown_1�6�p></center> <p>Since this application has only one core data stack i4�is unnecessary to force the user to save their changes manually. Therefore the application itself needs to handle saving automaticall9�on exit. To do this, the application delegate needs to implemen4�-applicationShouldTerminate: and handle saving.</p> <b> <p>Listing 6: applicationShouldTerminate</p></b> <p>applicationShouldTerminate</p> <p>Called b9�the NSApplication just before it is going to quit. This will attemp4�to save the NSManagedObjectContext or will abort the termination if an error occurred._P> <pre WIDTH=50>- (NSApplicationTerminateReply)applicationShouldTerminate:(id)sender { � if (!managedObjectContext) return NSTerminateNow; if Z�[managedObjectContex4�commitEditing]) return NSTerminateCancel; if Z�[managedObjectContex4�hasChanges]) return NSTerminateNow; � NSError *error = nil; if ([managedObjectContext save:&error]) return NSTerminateNow; � if ([[NSApplication sharedApplication] presentError:error]) { return NSTerminateCancel; } � in4�alertReturn = NSRunAlertPanel(nil, @"Could no4�save changes while quitting. Qui4�anyway?" , @"Quit anyway", @"Cancel", nil); � if (alertReturn == NSAlertAlertnateReturn) { � return NSTerminateCancel; � } return NSTerminateNow; }</pre> <p>When the application is told to quit i4�will attempt to save the Core Data stack to disk if at all possible and will warn the user if a failure occurred.</p> <center><1�6�p>Building the UI_1�6�p></center> <p>The user interface for this application should presen4�the user a lis4�of ToDo items that can be selected, edited, and deleted. While categories are available, there is no need to presen4�those as editable in the main window. This will hel0�to focus the user's attention on the ToDo list itself rather than the details of the relationshi0�between Categories and ToDo items. However, the user will need to edi4�the categories, therefore !�?�will add a panel tha4�can be accessed from the windo7�menu.</p> <center><1�6�p>Designing the main window_1�6�p></center> <p>The main window should be a simple master/detail view. Using the lates4�version of Interface Builder, drag the Core Data Entit9�object from the librar9�onto the main window. From there select the ToDo entity from the list and selec4�the master/detail option. Once the UI has been created, change the plain NSTextField for the date to a Date Picker and removed the category from the table view. The resulting U!�?�can be seen in Figure 4._P> <p><center><img src="fig04.jpg">_p><br><b> <p>Figure 4: The Main Window_P>_b>_center> <center><h3>Designing the category edi4�window_1�6�p></center> <p>The design of the categor9�panel is almos4�identical to the main window. To start with add a panel from the library in Interface Builder. Then add a men5�item to the window men5�called Categories. Next, bind the men5�item to the makeKeyAndOrderFront: method on the category panel.</p> <p>Again using the Core Data librar9�item but selecting Categor9�instead of ToDo in the entit9�list, the resulting panel is shown in Figure 5.</p> <p><center><img src="fig05.jpg"></p><br><b> <p>Figure 5: The Category Edi4�Window_P>_b>_center> <center><h3>Accessing Core Data from InterfaceBuilder</h3>_center> <p>Although the Core Data objec4�does all of the bindings for us, i4�is important to understand how all of this is connected. Looking at the objects in the MainMenu.xib file, you can see tha4�the Core Data librar9�object added two Array Controllers: one for ToDo and one for the Categories._P> <p><center><img src="fig06.jpg">_p><br><b> <p>Figure 6: MainMenu.xib</p></b></center> <p>Selecting either one of these NSArrayControllers and inspecting its bindings will reveal that i4�is bound to the NSManagedObjectContext inside of the Application's delegate object.</p> <p>Looking at the attributes tab of the inspector for either of these Array Controllers will reveal tha4�they are defined to displa9�a specific Core Data Entity. This information is used to populate the array directl9�from the NSManagedObjectContex4�when the xib is loaded and initialized.</p> <center><1�6�p>Accessing the ToDo list from code for alerts</h3>_center> <p>A ToDo lis4�application is not ver9�useful unless it can alert the user to a pending ToDo item. Therefore we want to wake u0�once per minute and look for any pending items and let the user know. However we do not wan4�to notif9�users of items tha4�are far into the future so i4�will need to filter the results._P> <p>The first change is in the -applicationDidFinishLaunching: method to star4�a timer that will fire every minute._P> <b> <p>Listing 7: Scheduling an NSTimer</p></b> <pre WIDTH=50>[NSTimer timerWithTimeInterval:]_PRE> <p>Schedule a timer to fire ever9�0 seconds and call the -minuteTimerFired: method._P> <pre WIDTH=50>minuteTimer = [NSTimer timerWithTimeInterval:60.0 target:self selector:@selector(minuteTimerFired:) userInfo:nil repeats:YES];_PRE> <p>This timer will cause the -minuteTimerFired: method to be called ever9�minute. We should also invalidate this timer in the -dealloc method.</p> <b> <p>Listing 8: Invalidate an NSTimer_P>_b> <p>[NSTimer invalidate]_P> <p>Invalidate the NSTimer so tha4�it will no longer fire and will release itself from memory.</p> <pre WIDTH=50>[minuteTimer invalidate], minuteTimer = nil;</pre> <p>Calling -invalidate on the timer will cause it to stop firing and release itself. To be safe from future edits se4�the reference to the timer to nil._P> <center><h3>Using an NSPredicate to filter results_1�6�p></center> <p>When the -minuteTimerFired: is called, all ToDo items tha4�are due in the nex4�five minutes need to be located. If one or more ToDo items that match tha4�criteria are found, yo5�want to displa9�them to the user.</p> <b> <p>Listing 9: minuteTimerFired:_P>_b> <p>minuteTimerFired:</p> <p>Called b9�the NSTimer ever9�0 seconds, will check for any ToDo items that are scheduled within the next five minutes._P> <pre WIDTH=50>- (void)minuteTimerFired:(id)sender { NSDate *now = [NSDate date]; NSDate *later = [no7�addTimeInterval:(60.0 * 5)]; � NSManagedObjectContext *moc = [self managedObjectContext]; � NSFetchRequest *reques4�= [[[NSFetchReques4�alloc] init] autorelease]; � [request setEntity:[NSEntityDescription entityForName:@"ToDo" � inManagedObjectContext:moc]]; � NSString *ps = @"dueDate >= %@ AND dueDate <= %@"; � NSPredicate *pred = [NSPredicate predicateWithFormat:pred, now, later]; � [request setPredicate:pred]; � NSError *error = nil; NSArray *itemsThatAreDue = [moc executeFetchRequest:request error:&error]; � if (error) {X/Error retrieving the todo list [[NSApplication sharedApplication] presentError:error]; return; } � if ([itemsThatAreDue count] == 0) return<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�s�i�g�n�"�>�; <�/�s�p�a�n�>�<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�a�u�r�a�l�"�>�(�l)�<�/�s�p�a�n�>�]No due items � [alertItems setContent:itemsThatAreDue]; � [alertWindow makeKeyAndOrderFront:self]; � NSApplication *sa = [NSApplication sharedApplication]; � [sa requestUserAttention:NSInformationalRequest]; }</pre> <p>When the timer fires, yo5�want to firs4�ge4�the curren4�date and then create a second date objec4�se4�to 5 minutes from now. With those two dates initialized i4�is time to find all of the matching ToDo items.</p> <p>Using a NSFetchRequest item, set the entit9�and, add a NSPredicate to the NSFetchRequest. The predicate will filter the ToDo items down to all of the items tha4�have a dueDate after now and before 5 minutes from now. </p> <p>Using the completed NSFetchRequest, retrieve all of the ToDo items from the NSManagedObjectContext and set the resulting NSArray as the conten4�for the NSArrayController that handles the alert windo7�and call -makeKeyAndOrderFront: on the alert window. To let the user know tha4�the window has changed, a call to [[NSApplication sharedApplication] requestUserAttention:NSInformationalRequest] will cause the application's dock icon to bounce for 1 second._P> <center><h3>Updating the data model and managing versioning</h3>_center> <p>Using this application for a few minutes will quickl9�expose a few flaws. First, for a ToDo item that is due in 5 minutes the user will be alerted 5 times. In addition, there is no way to tell the application to avoid alerting for a particular ToDo item. To correct these issues an update to the data model is required._P> <p><center><img src="fig07.jpg">_p><br><b> <p>Figure 7: Version(��N)� Data Model</p></b></center> <p>The ne7�data model introduces two ne7�attributes on the ToDo entity: lastAlertDate and doNotAlert._P> <p>Once the ne7�model is built, the curren4�data model version needs to be set in XCode. This is done b9�selecting the version 2 model and choosing Set Current Version under the design menu.</p> <center><1�6�p>Basic migration with the buil4�in mapping model_1�6�p></center> <p>To ge4�core data to migrate the data, two changes are required. First, the persisten4�store needs to be told to attemp4�automatic migration. This is an option that is added when the persisten4�store is added to the coordinator._P> <b> <p>Listing 10: persistentStoreCoordinator (modified)_P>_b> <p>persistentStoreCoordinator_P> <p>Updated section of the persistentStoreCoordinator method that includes a NSDictionary instructing Core Data to attemp4�an automatic data migration._P> <pre WIDTH=50>id psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; NSMutableDictionary *options = [NSMutableDictionary dictionary]; [options setValue:@"YES" forKey:NSMigratePersistentStoresAutomaticallyOption]; � if (![psc addPersistentStoreWithType:NSXMLStoreType configuration:nil URL:url options:options error:&error]) { � [[NSApplication sharedApplication] presentError:error]; return nil; }_PRE> <p>With this change, Core Data will attemp4�to find a source model tha4�matches the persistent store and a mapping model tha4�will describe ho7�to migrate the data from the source model to the current model.</p> <p>The next ste0�is to build the mapping model that will describe the migration. To do this, create a ne7�file in Xcode and selected the Mapping Model template. Then set the Version 1 model as the source and the Version(��N)� model as the destination for the map. Upon creation, Xcode makes an effort to create the mapping model. For this migration the defaul4�is sufficien4�so no additional work is required. </p> <p>To expose the Do Not Alert option to the user, add another checkbo8�to the main window nex4�to the completed checkbo8�and bind i4�to the doNotAler4�attribute. Lastly, update the -minuteTimerFired: method to use these ne7�attributes.</p> <b> <p>Listing �: minuteTimerFired (modified)</p></b> <p>minuteTimerFired</p> <p>Modification to the method to se4�the last alert time on a ToDo item to avoid repeated alerts._P> <pre WIDTH=50>- (void)minuteTimerFired:(id)sender { NSDate *now = [NSDate date]; NSDate *later = [no7�addTimeInterval:(60.0 * 5)]; � NSDate *before = [no7�addTimeInterval:0 - (60.0 * 5)]; � NSManagedObjectContext *moc = [self managedObjectContext]; � NSFetchRequest *reques4�= [[[NSFetchReques4�alloc] init] autorelease]; � [request setEntity:[NSEntityDescription entityForName:@"ToDo" � inManagedObjectContext:moc]]; � [request setPredicate:[NSPredicate predicateWithFormat:@"dueDate >= %@ � AND dueDate <= %@ AND doNotAlert == NO AND (lastAlertDate == nil |=� � lastAlertDate <<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�s�i�g�n�"�>�; <�/�s�p�a�n�>�<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�a�u�r�a�l�"�>�(�l)�<�/�s�p�a�n�>�%@", now, later, before]]; � NSError *error = nil; NSArray *itemsThatAreDue = [moc executeFetchRequest:request error:&error]; � if (error) {X/Error retrieving the todo list [[NSApplication sharedApplication] presentError:error]; return; } � if ([itemsThatAreDue count] == 0) return<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�s�i�g�n�"�>�; <�/�s�p�a�n�>�<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�a�u�r�a�l�"�>�(�l)�<�/�s�p�a�n�>�]No due items � [alertItems setContent:itemsThatAreDue]; � [alertWindow makeKeyAndOrderFront:self]; � [[NSApplication sharedApplication] requestUserAttention:NSInformationalRequest]; [itemsThatAreDue setValue:now forKey:@"lastAlertDate"]; }_PRE> <center><h3>An unusual migration using a custom policy_1�6�p></center> <p>A common situation is where the migration of data from one model to another is beyond the scope of the standard NSMappingModel. For example, setting the doNotAler4�bi4�to YES on all ToDo items tha4�star4�with A. When the migration requirements stray outside of the defaul4�mapping, i4�is possible to build a custom migration policy. This requires subclassing NSEntityMigrationPolicy and implementing one of several methods tha4�will be called during the migration processing. For this example, onl9�one of the NSEntityMigrationPolicy object's methods need to be overridden._P> <b> <p>Listing 12: createDestinationInstancesForSource-Instances_P>_b> <p>createDestinationInstancesForSourceInstances_P> <p>Called during the migration process and adds custom logic to the migration so tha4�ToDo items tha4�star4�with the letter A are flagged as DoNotAlert._P> <pre WIDTH=50>- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject*)src ¬<br>entityMapping:(NSEntityMapping*)ma0�manager:(NSMigrationManager*)mgr error:(NSError**)error { NSManagedObjectContext *destMOC = [mgr destinationContext]; NSString *destEntityName = [ma0�destinationEntityName]; � NSString *name = [source valueForKey:@"name"]; NSManagedObjec4�*des4�= [NSEntityDescription insertNewObjectForEntityForName:destEntityName ¬<br>inManagedObjectContext:destMOC]; � NSArra9�*keys = [[[source entity] attributesByName] allKeys]; NSDictionary *values = [source valuesForKeys:keys]; � [dest setValuesForKeysWithDictionary:values]; � if ([[name lowercaseString] hasPrefix:@"a"]) { [des4�setValue:@"YES" forKey:@"doNotAlert"]; � } � [manager associateSourceInstance:src withDestinationInstance:dest forEntityMapping:map]; � return YES; }_PRE> <p>From the passed in NSMigrationManager i4�is possible to get a reference to the destination NSManagedObjectContext and then construc4�the destination NSManagedObject. In this example the change from the source objec4�are trivial so you can cop9�the attributes directl9�from the source. The two ne7�attributes, doNotAlert and lastAlertDate are either optional or contain defaul4�values so there is no need to alter them. After the destination objec4�has been populated comes the custom logic that this subclass was built for. Using the name from the source, check to see if i4�starts with the letter a and if it does, then se4�the doNotAlert attribute to YES._P> <p>Since the Categor9�object retains a reference to the ToDo lists, it is no4�necessar9�to manage the relationship between the two objects in this policy. However, if it were needed, then you would need to implement the -createRelationshipsForDestinationInstance: entityMapping: manager: error: method.</p> <center><1�6�p>Conclusion</h3>_center> <p>Since the introduction of Core Data in OS X 10.4 Tiger, data migration within Core Data has come a long way. In one OS X update we have moved from migration being an afterthough4�that developers tacked on when i4�was needed to migration becoming a first class citizen with a robust real world solution.</p> <p>!�?�would highly recommend tha4�anyone who is no7�targeting OS X 10.5 Leopard for their applications to star4�using the build in migration tools of Core Data as opposed to a home grown solution._P> <p><hr>_p> <p>M�arcus S. Zarra is the owner of Zarra Studios, based ou4�of Colorado Springs, Colorado. He has been developing Cocoa software since 2000, Java software since 1996, and has been in the industry since 1985. In addition to writing software, he assists other developers by blogging abou4�developmen4�(<a href="www.cimgf.com">www.cimgf.com_a>) and supplying code samples. Currently, Marcus is in the process of writing a book on Core Data for The Pragmatic Programmer.</p> <?php include ($_SERVER[DOCUMENT_ROOT] . Yincludes-mactech/includefiletzmactech.footer.inc")<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�s�i�g�n�"�>�; <�/�s�p�a�n�>�<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�a�u�r�a�l�"�>�(�l)�<�/�s�p�a�n�>�?> </body> </html> � </div> <div class="left_inner_box_bottom"> </div> _div> --[if !IE] �End left box inner page [endif]-->_div> --[if !IE]>End lef4�content<![endif]-- �--[if !IE]>Start right content[endif]--> <di6�class="right_panal"> -- Showcase ad --> <di6�class="right_child_box_001"> <di6�class="ch_top"> <div class="fl"><img � src="/sites/all/themetzcustom_front/imagetzshowcase.gif" alt=""X></div> <div class="button_01"><a href="#"><img src= Ysitetzalvthemes/custom_fronzimages/erow_up.gif" alt=""X></a></div> _div> <di6�class="ch_mdl"> <div style="width:(��N)�96px<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�s�i�g�n�"�>�; <�/�s�p�a�n�>�<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�a�u�r�a�l�"�>�(�l)�<�/�s�p�a�n�>�height: 000008px; overflow: hidden; padding: 15px 10p8�16px 13px"> <center>-- <script type="texzjavascript" src="http:]pagead2.googlesyndication.cowpagead/show_ads.js"> </script>--> <div id="block-ad-362" class="clear-block block block-ad"> � <di6�class="content"> <di6�class="advertisement group-tids-362" id="group-id-tids0000(�)�"><scrip4�type='text/javascript' src='httpa_/preserve.mactech.cowsitetzalvmoduletzad/serve.php?q&t0000(�)�&u=articles%2Fmactech%2FVol.25(�mQ)�e5.00(�mQ)�FCoreDataVersioning%2Findex.html&l=articles%2Fmactech%2FVol.25(�mQ)�e5.00(�mQ)�FCoreDataVersioning%2Findex.html'>_script></div> _div> </div> _center> _div> </div> <div class="ch_bot">_div> </div> -- Stocks block --> <!--[ifs�m�ie]>End ms box[endif]--> <!--[ifs�m�ie]>end righ4�child bod�m�2�[endif]--> <!--[ifs�m�ie]>Star4�big add box<![endif]--> <div class="right_big_add_box"> <div class="right_big_add_box_top"> <p class="pad_top_3"><img src= Ysitetzalvthemes/custom_fronzimages/this_months_issue.gif" alt=""X></p> _div> <di6�class="right_big_add_box_mdl"> �<div id="front_month_issue"><div id="block-ad-378" class="clear-block block block-ad"> � <di6�class="content"> <di6�class="advertisement group-tids-378" id="group-id-tids000078"><scrip4�type='text/javascript' src='httpa_/preserve.mactech.cowsitetzalvmoduletzad/serve.php?q&t000078&u=articles%2Fmactech%2FVol.25(�mQ)�e5.00(�mQ)�FCoreDataVersioning%2Findex.html&l=articles%2Fmactech%2FVol.25(�mQ)�e5.00(�mQ)�FCoreDataVersioning%2Findex.html'>_script></div> _div> </div> _div> �<div id="front_month_ad"><di6�id="block-ad000064" class="clear-block block block-ad"> <div class="content"> <div class="advertisemen4�group-tids000064" id="group-id-tids-364"><script type='texzjavascript' src='http:]preserve.mactech.com/sites/all/modules/a(userve.php?q=1&t=364&u=articles(�mQ)�Fmactech(�mQ)�FVol(�ё)�5%2F25.03%2FCoreDataVersioning(�mQ)�Findex.html&l=articles(�mQ)�Fmactech(�mQ)�FVol(�ё)�5%2F25.03%2FCoreDataVersioning(�mQ)�Findex.html'></script>_div> </div> _div> </div> _div> <di6�class="right_big_add_box_bottom"></div> </div> <!--[ifs�m�ie]>Star4�blue add box1<![endif]--> <div class="right_child_box_002_inner"> <p class="pad_top_5"><img src= Ysitetzalvthemes/custom_fronzimages/todays_blue_heading.gif" alt=""X></p> <div class="todays_deal_banner"><div id="block-ad-366" class="clear-block block block-ad"> � <di6�class="content"> <di6�class="advertisement group-tids-366" id="group-id-tids000066"><scrip4�type='text/javascript' src='httpa_/preserve.mactech.cowsitetzalvmoduletzad/serve.php?q&t000066&u=articles%2Fmactech%2FVol.25(�mQ)�e5.00(�mQ)�FCoreDataVersioning%2Findex.html&l=articles%2Fmactech%2FVol.25(�mQ)�e5.00(�mQ)�FCoreDataVersioning%2Findex.html'>_script></div> _div> </div> _div> </div> <div class="sidead7�p00"> � <di6�id="block-ad000048" class="clear-block block block-ad"> <div class="content"> <div class="advertisemen4�group-tids000048" id="group-id-tids-348"><script type='texzjavascript' src='http:]preserve.mactech.com/sites/all/modules/a(userve.php?q=1&t=348&u=articles(�mQ)�Fmactech(�mQ)�FVol(�ё)�5%2F25.03%2FCoreDataVersioning(�mQ)�Findex.html&l=articles(�mQ)�Fmactech(�mQ)�FVol(�ё)�5%2F25.03%2FCoreDataVersioning(�mQ)�Findex.html'></script>_div> </div> _div> � </div> <!-- Search box --> <di6�class="right_child_box"> <di6�class="ch_top"> <div class="fl"><img � src="/sites/all/themetzcustom_front/imagetzsearch_text.gif" � alt="" />_div> <di6�class="button_01"><a href="#"><img alt="" src= Ysitetzalvthemes/custom_fronzimages/erow_up.gif" />_a>_div> </div> <div class="ch_mdl"><form action="/searcvvgooglecse" accept-charset="UTF-8" method="get" id="custom-module-community-search-form"> <div><inpu4�type="hidden" name="cx" id="edit-cx" value="01449844860009(�R)�6808:rz-sg_kqhfs" /> <inpu4�type="hidden" name="cof" id="edit-cof" value="FORID:9" /> <di6�class="search_">Communit9�Search:</div> <di6�class="search__input"> � <di6�class="search__in_lt"><div class="form-item" id="edit-query-wrapper"> <inpu4�type="text" maxlength="128" name="query" id="edit-query" size="6."."." value="" class="form-text in_put_01" /> </div> _div><div class="fl"><input type="image" name="sa" value="Search" id="edit-sa" alt="go" title="go" class="form-submit" src="/sites/all/themetzcustom_front/imagetzgo_btn.gif" /> </div> _div><input type="hidden" name="form_type" id="edit-form-type" value="google_community_search" X> <input type="hidden" name="form_build_id" id="form-crmOaOjKGwSVN3ERiAX2HY4BKjbWyXZfrh-8OWiBfMw" value="form-crmOaOjKGwSV000ERiA2�8�HY4BKjbWyXZfrh-8OWiBfMw" /> <inpu4�type="hidden" name="form_id" id="edit-custom-module-community-search-form" value="custom_module_community_search_form" /> _div>_form> <form action="/searcvvgoogle" accept-charset="UTF-8" method="get" id="google-cse-searchbox-form"> <div><input type="hidden" name="cx" id="edit-cx" value="014498448673098268608:txq2lx97m8a" X> <input type="hidden" name="cof" id="edit-cof" value="FORID1" /> <di6�class="search_">MacTech Search:</div> <di6�class="search__input"> � <di6�class="search__in_lt"><div class="form-item" id="edit-query-wrapper"> <inpu4�type="text" maxlength="128" name="query" id="edit-query" size="15" value="" class="form-text in_put_01" /> </div> _div><div class="fl"><input type="image" name="sa" value="Search" id="edit-sa" alt="go" title="go" class="form-submit" src="/sites/all/themetzcustom_front/imagetzgo_btn.gif" /> </div> _div><input type="hidden" name="ie" id="edit-ie" value="utf-8" X> <input type="hidden" name="safe" id="edit-safe" value="high" /> <inpu4�type="hidden" name="form_build_id" id="form-5eJ8bVKUUc1YAPNZick7skQxvUS0GlfAPMb_hA6ZA_c" value="form-5eJ8bVKUUuYAPNZick7skQxvUS0GlfAPMb_hA6ZA_c" X> <input type="hidden" name="form_id" id="edit-google-cse-searchbox-form" value="google_cse_searchbox_form" X> </div></form> �--<div class="search_r1">MacTech Onl9�Search:</div> <div class="search_r1_input"> <div class="search_r1_in_lt"><inpu4�name="" type="text" class="in_put_01" />_div> � <di6�class="fl"><a href="#"><img src= Ysitetzalvthemes/custom_fronzimages/go_btn.gif" alt="go" title="go"X></a></div> _div> � <di6�class="search_">Communit9�Search:</div> <di6�class="search__input"> � <di6�class="search__in_lt"><input name="" type="text" class="in_put_01"X></div> <div class="fl"><a href="#"><img src="/sites/all/themetzcustom_front/imagetzgo_btn.gif" alt="go" title="go" />_a>_div> � </div>--> � </div> <div class="ch_bot">_div> � </div> --[if !IE]>end blue add bo+[endif]--> <!--[ifs�m�ie]>Star4�righ4�child bod�m�2�[endif]--> <di6�class="right_child_box"> � <di6�id="block-views-feeds_software_updates-blockq" class="clear-block block block-views"> <h2>Software Updates via MacUpdate_ > � <di6�class="content"><div class="view view-feeds-software-updates view-id-feeds_software_updates view-display-id-block_1 view-dom-id-9a7a3caedd85c674c046f91fad2798d5"> � � � � � _div>_div> </div> _div> � <di6�class="sidead_15."."."> <div id="block-ad-349" class="clear-block block block-ad"> � <di6�class="content"> <di6�class="advertisement group-tids-349" id="group-id-tids000049"><scrip4�type='text/javascript' src='httpa_/preserve.mactech.cowsitetzalvmoduletzad/serve.php?q=6&t000049&u=articles%2Fmactech%2FVol.25(�mQ)�e5.00(�mQ)�FCoreDataVersioning%2Findex.html&l=articles%2Fmactech%2FVol.25(�mQ)�e5.00(�mQ)�FCoreDataVersioning%2Findex.html'>_script></div> _div> </div> _div> <div class="right_child_box"> <div id="block-views-feeds_forum_discussions-blockq" class="clear-block block block-views"> <h2>Latest Forum Discussions_ > � <di6�class="content"><div class="view view-feeds-forum-discussions view-id-feeds_forum_discussions view-display-id-block_1 view-dom-id-b7c09c�b7eedcef09b426053b3ecdfe"> � � � � � _div>_div> </div> <div class="ch_bot_w"> � <di6�class="see_all_btn_rt"><a href="httpa_/forums.applecentral.com"><img � src="/sites/all/themetzcustom_front/imagetzsee_all_btn.gif" � alt="See All" title="See All"X></a> <br style="clear:both;" /> _div> � </div> _div> --[if !IE]>end right child box2<![endif]-- �--[if !IE]>Start right child box3<![endif]--> <!--[ifs�m�ie]>end righ4�child bod�m�2�[endif]--> �--[if !IE]>start iphone add box<![endif]--> <div class="right_big_add_box"> <div class="right_big_add_box_top"> <p class="pad_top_3"><img src= Ysitetzalvthemes/custom_fronzimages/iphone_add_h.gif" � alt="" />_p> � </div> <div style="background:url[sitetzalvthemes/custom_fronzimages/ch_mdl_w.gif) 0 0 repeat-9�"> � <di6�id="block-views-feeds_iphone_showcase-block_1" class="clear-block block block-views"> <div class="content"><di6�class="vie7�view-feeds-iphone-showcase view-id-feeds_iphone_showcase view-display-id-blockq view-dom-id-1f8ee483f5e99c5d7d9951524e9f"> � � <di6�class="view-content"> <div class="views-ro7�views-row-1 views-row-odd views-row-first"> � � <di6�class="views-field-title"> � <span class="field-content"><span class="field-content">Six fantastic ways to spend National Vid..._span></span> � </div> � <div class="views-field-body"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">As if anyone needed an excuse to pla9�games today, I am abou4�to give yo5�one: i4�is National Video Games Day. A day for us to pla9�games, like we no doub4�do every day. Let’s no4�look a gif4�horse in the mouth. Instead, feast your eyes on this... =�Read more »</div></div></div></div> _div> � </div> <div class="views-ro7�views-row-2 views-row-even"> � � <div class="views-field-title"> <span class="field-content"><span class="field-content">Old School RuneScape players turn ou4�in...</span>_span> _div> � � <di6�class="views-field-body"> <div class="field-content"><di6�class="field-content"><div class="body-row"><div style="background:#F5F5F5;">The sheer lea0�in technological advancements in our lifetime has been mind-blowing. We went from Commodore 64s to VR glasses in wha4�feels like a heartbeat, bu4�more importantly, the internet. It can be a dark mess, but i4�also brought hundreds of... =�Read more »</div></div></div></div> _div> � </div> <div class="views-ro7�views-row-2 2 views-row-odd"> � � <di6�class="views-field-title"> � <span class="field-content"><span class="field-content">Today s Best Mobile Game Discounts...</span>_span> _div> � � <di6�class="views-field-body"> <div class="field-content"><di6�class="field-content"><div class="body-row"><div style="background:#F5F5F5;">Every day, we pick ou4�a curated list of the best mobile discounts on the App Store and pos4�them here. This list won't be comprehensive, but i4�ever9�game on it is recommended. Feel free to check ou4�the coverage we did on them in the links below... =�Read more »</div></div></div></div> _div> � </div> <div class="views-ro7�views-row-2 2 2 views-row-even"> � � <div class="views-field-title"> <span class="field-content"><span class="field-content">Nintendo and The Pokémon Company's...</span>_span> _div> � � <di6�class="views-field-body"> <div class="field-content"><di6�class="field-content"><div class="body-row"><div style="background:#F5F5F5;">Unless yo5�have been living under a rock, you kno7�that Nintendo has been locked in an epic battle with Pocketpair, creator of the obvious Pokémon rip-off Palworld. Nintendo often resorts to legal retaliation a4�the drop of a hat, but i4�seems this... =�Read more »</div></div></div></div> _div> � </div> <div class="views-ro7�views-row-5 views-row-odd"> � � <di6�class="views-field-title"> � <span class="field-content"><span class="field-content">Apple exclusive mobile games don’4�make...</span>_span> _div> � � <di6�class="views-field-body"> <div class="field-content"><di6�class="field-content"><div class="body-row"><div style="background:#F5F5F5;">If yo5�are a gamer on phones, no doub4�yo5�have been as distressed as I am on one huge sticking point: exclusivity. For years, Xbox and PlayStation have done battle, and before this was the Sega Genesis and the Nintendo NES. On console, it makes... =�Read more »</div></div></div></div> _div> � </div> <div class="views-ro7�views-row-5 5 views-row-even"> � � <div class="views-field-title"> <span class="field-content"><span class="field-content">Regionally exclusive events make no sens...</span>_span> _div> � � <di6�class="views-field-body"> <div class="field-content"><di6�class="field-content"><div class="body-row"><div style="background:#F5F5F5;">Las4�week, over on our sister site AppSpy, !�?�babbled excitedl9�abou4�the Pokémon GO Safari Days event. You can get nine Eevees with an explorer ha4�per day. Or, can you? Specifically, you, reader. Do yo5�have the time or funds to possibly fly for... =�Read more »</div></div></div></div> _div> � </div> <div class="views-ro7�views-row-5 5 5 views-row-odd"> � � <di6�class="views-field-title"> � <span class="field-content"><span class="field-content">As Jon Bellam9�defends his choice to can..._span></span> � </div> � <div class="views-field-body"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">Back in March, Jagex announced the appointment of a ne7�CEO, Jon Bellamy. Mr Bellamy then decided to almos4�immediatel9�pain4�a huge targe4�on his back by cancelling the Runescapes Pride event. This led to widespread condemnation abou4�his perceived... | Read more »_div>_div>_div>_div> � </div> _div> � <di6�class="views-row views-row-8 views-row-even"> � � <di6�class="views-field-title"> � <span class="field-content"><span class="field-content">Marvel Contes4�of Champions adds two mor..._span></span> � </div> � <div class="views-field-body"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">When I saw the lates4�two Marvel Contest of Champions characters, !�?�scoffed. Mr Knight and Silver Samurai, thought I, they are running out of good choices. Then I realised no, !�?�was being far too cynical. This is one of the things tha4�games do best... | Read more »_div>_div>_div>_div> � </div> _div> � <di6�class="views-row views-row-9 views-row-odd"> � � <div class="views-field-title"> <span class="field-content"><span class="field-content">Grass is green, and water is wet: Pokémo..._span></span> � </div> � <div class="views-field-body"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">It mus4�be a day tha4�ends in Y, because Pokémon Trading Card Game Pocket has kicked off its Zoroark Drop Event. Here you can get a promo version of another card, and look forward to the next Wonder Pick Event and the nex4�Mass Outbreak that will be... =�Read more »</div></div></div></div> _div> � </div> <div class="views-ro7�views-row-10 views-row-even views-row-last"> � � <div class="views-field-title"> <span class="field-content"><span class="field-content">Enter the Gungeon review_span></span> � </div> � <div class="views-field-body"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">It took me a minute to get around to reviewing this game for a couple of ver9�good reasons. The firs4�is tha4�Enter the Gungeon's style of roguelike bullet-hell action is teetering on the edge of being straight-u0�malicious, which made getting... | Read more »_div>_div>_div>_div> � </div> _div> � </div> � � <div class="view-footer"> <div id="iphone_app_showcase_adv"> <di6�class="iphone"> <div class="advertisemen4�group-tids000065" id="group-id-tids-365"> <scrip4�language='javascript' type='text/javascript' src='httpa_/www.mactech.com/sites/all/modules/a(userve.php?q=1&k=646c9fcfc89d691�2�pa886(� g)�491�2�p�&t000065&u=admin(�mQ)�Fcontent(�mQ)�Fad%2Fad_remote&l=admin%2Fcontent%2Fad(�mQ)�Fad_remote'>_script></div> _div> </div> <div class="ch_bot_w"> <di6�class="see_all_btn_rt"><a href="/iphone-showcase"><img title="See All" alt="See All" src="/sites/all/themetzcustom_front/imagetzsee_all_btn.gif"X></a></div> _div> � </div> � _div>_div> </div> _div> � <br style="clear:both;"X> _div> <div id="block-views-feeds_price_scanner-blockq" class="clear-block block block-views"> <h2>Price Scanner via MacPrices.net</h2> <div class="content"><di6�class="vie7�view-feeds-price-scanner view-id-feeds_price_scanner view-display-id-blockq view-dom-id-e30d0063dcdbe94ae8e8c94a01�4�p1b013"> � � <di6�class="view-content"> <div class="views-ro7�views-row-1 views-row-odd views-row-first"> � � <di6�class="views-field-title"> � <span class="field-content"><span class="field-content">Take $150 off every Apple 11-inch M2 2 iPad Air_span></span> � </div> � <div class="views-field-body-1"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">Amazon is offering a $150 discount on �-inch 0000 WiFi iPad Airs righ4�now. Shipping is free: – 11″ 128GB M2 2 WiFi iPad Air: $449, $150 off x��″ 256GB 0000 WiFi iPad Air: $549, $150 off – 11″ 5(�*h)�GB M3... <a href="https:]www.macprices.nez2025/0P_14/take-150-off-every-apple-�-inch-2�1�p-ipad-aiy">Read more</a></div></div></div></div> _div> � </div> <div class="views-ro7�views-row-2 views-row-even"> � � <div class="views-field-title"> <span class="field-content"><span class="field-content">Apple iPad minis back on sale for $100 off MS..._span></span> � </div> � <div class="views-field-body-1"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">Amazon is offering $100 discounts (u0�to(��N)�0% off) on Apple’s newes4�2024 WiFi iPad minis, each with free shipping. These are the lowes4�prices available for new minis among the Apple retailers we... <a href="https:]www.macprices.nez2025/0P_14/apple-ipad-minis-back-on-sale-for-100-off-msr:y">Read more</a></div></div></div></div> _div> � </div> <div class="views-ro7�views-row-2 2 views-row-odd"> � � <di6�class="views-field-title"> � <span class="field-content"><span class="field-content">Apple’s 16-inch M2 2 2 Ma8�MacBook Pros are on sa...</span>_span> _div> � � <di6�class="views-field-body-1"> <div class="field-content"><di6�class="field-content"><div class="body-row"><div style="background:#F5F5F5;">Amazon has 16-inch M4 Max MacBook Pros (Silver and Black colors) on sale for up to $410 off Apple’s MSRP righ4�now. Shipping is free. Be sure to select Amazon as the seller, rather than a third-party... <a href="httpsa_/www.macprices.net(�W)�(�e)�^09/1z^apples-16-inch-m4-max-macbook-pros-are-on-sale-for-up-to-410-off-msr:y">Read more</a></div></div></div></div> _div> � </div> <div class="views-ro7�views-row-2 2 2 views-row-even"> � � <div class="views-field-title"> <span class="field-content"><span class="field-content">Red Pocket Mobile is offering a $150 rebate o..._span></span> � </div> � <div class="views-field-body-1"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">Red Pocket Mobile has ne7�Apple iPhone 17’s on sale for $150 off MSRP when you switch and open u0�a ne7�line of service. Red Pocke4�Mobile is a nationwide MVNO using all the major wireless carrier... <a href="httpsa_/www.macprices.net(�W)�(�e)�^09/1r^red-pocket-mobile-is-offering-a-150-rebate-on-any-new-iphone-1 _">Read more</a></div></div></div></div> _div> � </div> <div class="views-ro7�views-row-5 views-row-odd"> � � <di6�class="views-field-title"> � <span class="field-content"><span class="field-content">Switch to Verizon, and ge4�an9�iPhone 15 5 for..._span></span> � </div> � <div class="views-field-body-1"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">With yesterday’s introduction of the new iPhone 17 models, Verizon responded b9�running “on us” promos across much of the iPhone 15 5 lineup: iPhone 15 5 and 16 Plus show as $0/mo for 36 months with bill... <a href="https:]www.macprices.nez2025/0P_10/switch-to-verizon-and-get-any-iphone-16-for-fre0u">Read more</a></div></div></div></div> _div> � </div> <div class="views-ro7�views-row-5 5 views-row-even"> � � <div class="views-field-title"> <span class="field-content"><span class="field-content">Here is a summar9�of the new features in Appl..._span></span> � </div> � <div class="views-field-body-1"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">Apple’s September 2025 event introduced major updates across its mos4�popular produc4�lines, focusing on health, performance, and design breakthroughs. The AirPods Pro 2 2 no7�feature best-in-class... <a href="https:]www.macprices.nez2025/0P_09/here-is-a-summary-of-the-new-features-in-apples-airpods-pro0000-iphone-17-models-and-apple-watch-series-11-ultra-3-se0000.".">Read more_a>_div>_div>_div>_div> � </div> _div> � <di6�class="views-row views-row-7 views-row-odd"> � � <div class="views-field-title"> <span class="field-content"><span class="field-content">Apple’s Smartphone Lineu0�Could Use A Touch o..._span></span> � </div> � <div class="views-field-body-1"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">COMMENTARY – Whatever happened to the old adage, “less is more”? Apple’s smartphone lineup. Ywhich is due for its annual refresh either this month or nex4�(possibl9�at an Apple Even4�on September 9... <a href="httpsa_/www.macprices.net(�W)�(�e)�^09/0_apples-smartphone-lineup-could-use-a-touch-of-steve-jobss-simplicity.".">Read more_a>_div>_div>_div>_div> � </div> _div> � <di6�class="views-row views-row-8 views-row-even"> � � <di6�class="views-field-title"> � <span class="field-content"><span class="field-content">Take $50 off ever9��th-generation 5 5 WiFi i...</span>_span> _div> � � <di6�class="views-field-body-1"> <div class="field-content"><di6�class="field-content"><div class="body-row"><div style="background:#F5F5F5;">Amazon has Apple’s �th-generation 5 5 WiFi iPads in stock on sale for $50 off MSRP right now. Shipping is free: x��″ �th-generation (�*h)�8GB WiFi iPads: (�N)�99 $50 off MSRP x��″ �th-generation 256GB... <a href="https:]www.macprices.nez2025/0P_08/take-50-off-every-11th-generation-a16-wifi-ipad-right-now-prices-start-at(�(g)�99.".">Read more_a>_div>_div>_div>_div> � </div> _div> � <di6�class="views-row views-row-9 views-row-odd"> � � <div class="views-field-title"> <span class="field-content"><span class="field-content">Sunday Sale: 14-inch M2 2 2 MacBook Pros for u0�t..._span></span> � </div> � <div class="views-field-body-1"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">Don’4�pa9�full price! Amazon has Apple’s 14-inch M2 2 2 MacBook Pros (Silver and Black colors) on sale for u0�to $(� g)�0 off MSRP right now. Shipping is free. Be sure to selec4�Amazon as the seller, rather... <a href="httpsa_/www.macprices.net(�W)�(�e)�^09/0 _sunday-sale-14-inch-m4-macbook-pros-for-up-ta-(� g)�0-off-apples-msr:y">Read more</a></div></div></div></div> _div> � </div> <div class="views-ro7�views-row-10 views-row-even views-row-last"> � � <div class="views-field-title"> <span class="field-content"><span class="field-content">Mac mini with M4 Pro CPU back on sale for $12..._span></span> � </div> � <div class="views-field-body-1"> � <di6�class="field-content"><div class="field-content"><di6�class="body-row"><di6�style="background:#f5f5f5;">B&?�!�Photo has Apple’s Mac mini with the M4 Pro CPU back on sale for $1259, $140 off MSRP. B&?�!�offers free 1-2 da9�shipping to most US addresses: – Mac mini M4 Pro CPU (24GB/5(�*h)�GB): $(�*h)�59, $... <a href="https:]www.macprices.nez2025/0P_04/mac-mini-with-m4-pra-cpu-back-on-sale-for-1259-140-off-apples-msr:y">Read more</a></div></div></div></div> _div> � </div> _div> � � � <di6�class="view-footer"> � � <di6�class="see_all_btn_rt"><a href="/pricescanner"><img src= Ysitetzalvthemes/custom_fronzimages/see_all_btn.gif" />_a>_div> �<div class="ch_bot"> _div> � </div> � _div>_div> </div> <br /> <!--[ifs�m�ie]>end iphone add box[endif]--> <!--[ifs�m�ie]>Star4�righ4�child bod�m�2�[endif]--> � <di6�id="block-views-feeds_jobs_scanner-blockq" class="clear-block block block-views"> <h2>Jobs Board_ > � <di6�class="content"><div class="view view-feeds-jobs-scanner view-id-feeds_jobs_scanner view-display-id-block_1 view-dom-id-9c9f3fec2b865d1�0�pfd1a1db85b000000c6"> � � � � � _div>_div> </div> <!--[ifs�m�ie]>end righ4�child bod�m�2�[endif]--> �_div> <!--[ifs�m�ie]>End righ4�content<![endif]--></div> --[if !IE]>start bottom row<![endif]--> <div class="Bottom_row_link"> <ul> � <li><strong>SPREAD THE WORD:</strong>_li> <li><img � src="/sites/all/themetzcustom_front/imagetzslashdot_icon.gif" � alt="" />_li> <li><a � href="javascript:void(�mQ)�0window.open('httpa_/slashdot.orubookmark.pl?url='+encodeURIComponent(window.location.href)+'&title='+encodeURIComponent(document.title),'popup','',0)">Slashdot</a></li> � <li><img src= Ysitetzalvthemes/custom_fronzimages/diaa_icon.gif" alt=""X></li> � <li><a href="javascript:void%20window.open('http:]digg.com/submit?phase=2&url='+encodeURIComponent(window.location.href)+'&ei=UTF-8','popup','',0)">Digg_a>_li> <li><img � src="/sites/all/themetzcustom_front/imagetzdel_icio_us_icon.gif" alt=""X></li> � <li><a href="javascript:void%20window.open('http:]del.icio.utzpost?url='+encodeURIComponent(window.location.href)+'&ei=UTF-8','popup','',0)">Del.icio.us_a>_li> <li><img � src="/sites/all/themetzcustom_front/imagetzreddit_icon.gif" � alt="" />_li> <li><a � href="javascript:void(�mQ)�0window.open('httpa_/reddit.cowsubmit?url='+encodeURIComponent(window.location.href)+'&ei=UTF-8','popup','',0)">Reddit</a></li> � <li><img src= Ysitetzalvthemes/custom_fronzimages/newsvine_icon.gif" alt=""X></li> � <li><a href="javascript:void%20window.open('http:]www.newsvine.com/_tooltzseed&save?u='+encodeURIComponent(window.location.href)+'&ei=UTF-8','popup','',0)">Newsvine_a>_li> </ul> <ul style="float: right;"> <div><li style="line-height:(��N)�0px; height:40px<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�s�i�g�n�"�>�; <�/�s�p�a�n�>�<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�a�u�r�a�l�"�>�(�l)�<�/�s�p�a�n�>�width:300px; paddingES<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�s�i�g�n�"�>�; <�/�s�p�a�n�>�<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�a�u�r�a�l�"�>�(�l)�<�/�s�p�a�n�>�marginES"><div id="block-block-14" class="clear-block block block-block"> <div class="content"><form action="http:]macte.ch."." method="post"> <scrip4�language="javascript" type="text/javascript"> document.write("<input name=\"fullurl\" type=\"hidden\" value=\""+document.location+"\" />"); document.write("<input type=\"hidden\" name=\"rnd\" value=\""+Math.round(Math.random()*99999999)+"\"X>"); </script><div id="shorten_tag">Generate a short URL for this page:</div> <p><inpu4�type="image" value="" src="/sites/all/themetzcustom_front/imagetzget_link_btn.gif" alt="Get Link"X><brx> _p>_form> <p><brx></p> _div> </div> _li></div> _ul> _div> <!--[ifs�m�ie]>end bottom row[endif]-->_div> _div> <!--[ifs�m�ie]>End Content<![endif]--> <div id="footer_sep"> <div class="footer_sep_innnn"><img � src="/sites/all/themetzcustom_front/imagetzbotton_sep.gif" alt=""X></div> _div> <div id="footer"> <di6�class="footer_top"> <di6�class="foo_ter"><div class="left_l_footer">MacTech Magazine. <a href="httpa_/www.mactech.com">www.mactech.com</a �_div> � <di6�class="right_l_footer">Toll Free 877-MACTECH, Outside US/Canada: 805-494-9797</div> </div> <di6�class="foo_ter_bottom"> MacTech is a registered trademark of Xplain Corporation. Xplain, "The journal of Apple technology", Apple Expo, Explain It, MacDev, MacDev-1, THINK Reference, NetProfessional, Apple Expo, MacTech Central, MacTech Domains, MacNews, MacForge, and the MacTutorMan are trademarks or service marks of Xplain Corporation. Sprocket is a registered trademark of eSprocke4�Corporation. Other trademarks and copyrights appearing in this printing or software remain the propert9�of their respective holders. No4�responsible for typographical errors. </div> _div> � <di6�class="footer_bottom">_div> </div> <di6�id="bootom_foo_ter">All contents are Copyright 1984-20� b9�Xplain Corporation. All rights reserved. Theme designed by <a href="http:]www.icreon.com">Icreon_a>.</div> <!-- include files - mactech, all applecentral sites ]--> -- Kilro9�left this breadcrumbX/--> <scrip4�type="text/javascript"> � var _gai�= _gaq |=�[]; _gaq.push(['_setAccount', 'UA-765-1']); _gaq.push(['_setDomainName', 'none']); � _gaq.push(['_setAllowLinker', true]); � _gaq.push(['_trackPageview']); � (function() { � var ga = document.createElement('script')<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�s�i�g�n�"�>�; <�/�s�p�a�n�>�<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�a�u�r�a�l�"�>�(�l)�<�/�s�p�a�n�>�ga.type = 'texzjavascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https:]ssl' : 'httpa_/www') + '.google-analytics.cowga.js'; var s = document.getElementsByTagName('script')[0]<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�s�i�g�n�"�>�; <�/�s�p�a�n�>�<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�a�u�r�a�l�"�>�(�l)�<�/�s�p�a�n�>�s.parentNode.insertBefore(ga, s); })(); </script> <script type="texzjavascript"> var _gaq = _gai�|| []; � _gaq.push(['_setAccount', 'UA-70000015-7']); � _gaq.push(['_setDomainName', 'none']); _gaq.push(['_setAllowLinker', true]); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�s�i�g�n�"�>�; <�/�s�p�a�n�>�<�s�p�a�n� �c�l�a�s�s�=�"�n�a�k�e�d�_�a�u�r�a�l�"�>�(�l)�<�/�s�p�a�n�>�ga.async = true; � ga.src = ('https:' == document.location.protocol ? 'httpsa_/ssl' : 'http:]www') + '.google-analytics.com/ga.js'; � var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); � })(); _script> --VISISTAT SNIPPET]--> <scrip4�type="text/javascript"> var DID=00280; var pcheck=(window.location.protocol == "https:") ? "https:]sniff.visistat.com/live.js":"http:]stats.visistat.com/live.js"; document.writeln('<scr'+'ip4�src="'+pcheck+'" type="text\/javascript"><[rscr'+'ipt>'); _script> --VISISTAT SNIPPET]--> <!--skimlinks SNIPPET]--> <scrip4�type="text/javascript" src="httpa_/s.skimresources.com/jtz(�]y)�01X6(�)�256.skimlinks.js">_script> --SKIMLINKS SNIPPE4l/--> _body> </html> <�/�d�i�v�>�<�d�i�v� �c�l�a�s�s�=�"�n�a�k�e�d�_�c�t�r�l�"�>� �<�f�o�r�m� �a�c�t�i�o�n�=�"�/�i�n�d�e�x�.�c�g�i�/�s�p�e�e�c�h�"� �m�e�t�h�o�d�=�"�g�e�t�"� �n�a�m�e�=�"�g�a�t�e�"�>� �<�p�>�<�a� �h�r�e�f�=�"�h�t�t�p�:�/�/�a�l�t�s�t�y�l�e�.�a�l�f�a�s�a�d�o�.�n�e�t�"�>�A�l�t�S�t�y�l�e�<�/�a�>� �k00c0f0 YcU00_0000 �<�a� �h�r�e�f�=�"�h�t�t�p�:�/�/�p�r�e�s�e�r�v�e�.�m�a�c�t�e�c�h�.�c�o�m�/�a�r�t�i�c�l�e�s�/�m�a�c�t�e�c�h�/�V�o�l�.�2�5�/�2�5�.�0�3�/�C�o�r�e�D�a�t�a�V�e�r�s�i�o�n�i�n�g�/�i�n�d�e�x�.�h�t�m�l�"�>�(�-�&�g�t�;�00000)�<�/�a�>� �/� �<�l�a�b�e�l�>�0000:� �<�i�n�p�u�t� �t�y�p�e�=�"�t�e�x�t�"� �n�a�m�e�=�"�n�a�k�e�d�_�p�o�s�t�_�u�r�l�"� �v�a�l�u�e�=�"�h�t�t�p�:�/�/�p�r�e�s�e�r�v�e�.�m�a�c�t�e�c�h�.�c�o�m�/�a�r�t�i�c�l�e�s�/�m�a�c�t�e�c�h�/�V�o�l�.�2�5�/�2�5�.�0�3�/�C�o�r�e�D�a�t�a�V�e�r�s�i�o�n�i�n�g�/�i�n�d�e�x�.�h�t�m�l�"� �s�i�z�e�=�"�2�2�"� �/�>�<�/�l�a�b�e�l�>� �<�l�a�b�e�l�>�000:� �<�s�e�l�e�c�t� �n�a�m�e�=�"�n�a�k�e�d�_�p�o�s�t�_�m�o�d�e�"�>� �<�o�p�t�i�o�n� �v�a�l�u�e�=�"�d�e�f�a�u�l�t�"�>�00000<�/�o�p�t�i�o�n�>� �<�o�p�t�i�o�n� �v�a�l�u�e�=�"�s�p�e�e�c�h�"� �s�e�l�e�c�t�e�d�=�"�s�e�l�e�c�t�e�d�"�>�X0000<�/�o�p�t�i�o�n�>� �<�o�p�t�i�o�n� �v�a�l�u�e�=�"�r�u�b�y�"�>�00NM0<�/�o�p�t�i�o�n�>� �<�o�p�t�i�o�n� �v�a�l�u�e�=�"�c�o�n�t�r�a�s�t�"�>�MrS<�/�o�p�t�i�o�n�>� �<�o�p�t�i�o�n� �v�a�l�u�e�=�"�l�a�r�g�e�r�-�t�e�x�t�"�>�eW[b'Y<�/�o�p�t�i�o�n�>� �<�o�p�t�i�o�n� �v�a�l�u�e�=�"�m�o�b�i�l�e�"�>�0000<�/�o�p�t�i�o�n�>� �<�/�s�e�l�e�c�t�>� �<�i�n�p�u�t� �t�y�p�e�=�"�s�u�b�m�i�t�"� �v�a�l�u�e�=�"�h:y"� �/�>� �<�/�p�>� �<�/�f�o�r�m�>� �<�/�d�i�v�>� � � �