Split iOS code in different files

Introduction:

Hello readers,

Organising source code in multiple files plays an essential role in managing content during software development. Modularisation becomes demanded as the project size grows.

go-back-gallery-for-pulling-hair-out-clipart-xosngi-clipart

We uses OO approach by keeping single responsibility principle in mind to manage them in different components and layers by interacting their instances.

The problem arises at a point when we might need to manage code of same instance in different files.

Apple provides a feature of Extension and Category. In swift, we have concept of extension (same as category in swift) which can keep the implementation as well, but the case with Objective-C is quite different. In case of Objective-C, we have a facility to create Categories that allow feature extension and also saves the effort of subclassing, but with a limitation of declaring variables in it. Extension in Objective-C fills this space and completes the need.

I would demonstrate the implementations for both Swift and Objective-C by managing Core data (system generated) code in different files.

Swift:

Create a new Xcode project with Single view application by keeping CoreData enabled.

As a next step create a new Swift file named as AppDelegate_CoreData.swift.

Check out the image and the description for further details:

create-a-core-data-extension

after creating this extension we are left with this code in AppDelegate:

app-delegate-after-creating-extension

If you will notice we are just calling “saveContext” function from AppDelegate leaving its implementation in another file. We can also take care of the “persistentContainer” property but it is not our concern for the time being.

Complete Source code:

AppDelegate.swift

 func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = {

return self.getContainer()

}()

AppDelegate_CoreData.swift

import CoreData

extension AppDelegate {
    
    
    // MARK: - Core Data Saving support
    
    func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() 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.
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }
    
    func getContainer() -> NSPersistentContainer
    {
        /*
         The persistent container for the application. This implementation
         creates and returns a container, having loaded the store for the
         application to it. This property is optional since there are legitimate
         error conditions that could cause the creation of the store to fail.
         */
        let container = NSPersistentContainer(name: "SplitCodeInFiles")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() 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.
                
                /*
                 Typical reasons for an error here include:
                 * The parent directory does not exist, cannot be created, or disallows writing.
                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                 * The device is out of space.
                 * The store could not be migrated to the current model version.
                 Check the error message to determine what the actual problem was.
                 */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        
        return container
    }
}

You can try it out as well.

Objective-C:

Objective-C way for this workaround is a bit different. I would suggest to encapsulate an extension inside Category to manage both the new variables and the functionality.

Here is a screenshot for a created category along with extension.

create-category

Implementation goes here:

move-core-data-code-in-category

Now we are left with this in the AppDelegate:

app-delegate

We have to include the category in the app delegate and thus we can access the “saveContext” function.

Extension definition:

@interface AppDelegate (CoreData)
{
    
}

- (void)saveContext;

@end

// Extension
@interface AppDelegate()
{
    NSPersistentContainer *container;
}

@end

Extension implementation:

#pragma mark - Core Data stack

- (NSPersistentContainer *)persistentContainer {
    
    @synchronized (self) {
     
        if (container == nil) {
            container = [[NSPersistentContainer alloc] initWithName:@"SplitCodeInFilesObjC"];
           [container loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
                if (error != nil) {
                    // 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.
                    
                    /*
                     Typical reasons for an error here include:
                     * The parent directory does not exist, cannot be created, or disallows writing.
                     * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                     * The device is out of space.
                     * The store could not be migrated to the current model version.
                     Check the error message to determine what the actual problem was.
                     */
                    NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                    abort();
                }
            }];
        }
    }

   return container;
}

#pragma mark - Core Data Saving support

- (void)saveContext {
    NSManagedObjectContext *context = self.persistentContainer.viewContext;
    NSError *error = nil;
    if ([context hasChanges] && ![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();
    }
}

Conclusion:

With this post we have learned how to manage code in using categories and extensions for both Swift and Objective-C way.

Feedback are the way to improve the strength of the post which is welcome. Feel free to share your thoughts.

References:

http://www.clipartkid.com/pulling-hair-out-cliparts/

Regards,

Shahan Ayyub

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s