I have created my first complex OS X application. While working on it, I've had some doubts about how I use the class that implements the NSApplicationDelegate protocol (the class Xcode creates by default for Cocoa applications, i.e. MyApplicationAppDelegate.m/h).
In many tutorials (and books), I see that people create an AppController class to manage main or generic application tasks. I prefer to add my generic tasks directly into MyApplicationAppDelegate and create specific controllers depending on the modules I need to manage.
For example, I add into MyApplicationAppDelegate every IBAction used to open other windows (i.e. opening a preference panel), every function that isn't strictly connected with a specific module/controller and IBOutlets for the main interface. In MyApplicationAppDelegate I also add every reference to controllers used in my application. That's essentially about it.
I'm really confused because I'm not sure whether or note this is good design. Has MyApplicationAppDelegate been designed for some other purpose?
I would like any suggestions and if possible any articles you might know of about design patterns for Cocoa.
Xcode used not to create an application delegate class in the Cocoa Application template by default.
I believe Apple only introduced the automatic creation of an <AppName>_AppDelegate class with their project template fairly recently, maybe in version 3.2 or so.
This is why many older books and tutorials have you create an AppController class, because the old project template did not create one for you.
You are free to use the <AppName>_AppDelegate as your main controller class, and the reason Apple adds it to their template is that so many developers use the NSApplicationDelegate object as their main application controller.
An excellent resource to learn more about design patterns in Cocoa is the book appropriately called Cocoa Design Patterns.
Related
I'm building a project that includes an MVC Web Api hosted in Azure and an iOS app. I'm trying to use Xamarin to build the app. As I understand it, I should use a portable class library in my Xamarin project to allow me to share the code between my Web Api project and the Xamarin app, as well as any future apps on other platforms like android.
So right off the bat I would want to put my models in the portable library. The app and the web api will pass those models back and forth. But the portable library doesn't have the Azure Table Storage library. It doesn't even have some very basic stuff. My models need to reference the Azure Storage Library so I can save instances to storage.
What is the best way to make this code shareable? Obviously I need to duplicate my model classes so they can exist in each location. But should those in the PCL inherit from those in the Web Api project? Vice versa? Should there be an interface that both inherit from (actually the Azure Table Storage library requires the classes to inherit from ITableEntity already...). Just looking for the best way to share these classes between the Web Api project and the PCL used by the Xamarin project.
Using a PCL - Portable Class Library is a great way to get started! There are a few quirks that you may want to understand prior to sharing your code.
The PCL Profile is a limited set of APIs available. Meaning that certain classes/assemblies might not be included. You can typically look up the class/assembly via MSDN and see if it has a PCL icon next to the class name.
If the library you are trying to use has assemblies not inside the current PCL Profile but can be found on the native platforms, you will want to use the IoC/DI pattern.
Hopefully the library you're using supports PCL. Otherwise, you will need a library that does support the PCL Profile. (You can check this by downloading the .nupkg, extracting, and looking at the libs folder). Note: You may want to check the Prerelease NuGet channel for PCL support. Sometimes you can find an open source project and remove/replace certain assemblies/code to make it Portable.
General Guidelines:
Keep your POCO classes simple in the PCL. If you have platform specific quirks you need to add to the models, make a Model layer on that platform that inherits from your simple PCL models. EX: Your Web API has a specific [Attribute] tag or interface that you need to apply to your model. You might already have a Model such as Person which is a simple POCO class in your PCL, and then you can create a PersonApiEntity model which might inherit Person and any platform-specific APIs you need to apply to it.
It seems ITableEntity/TableEntity is not supported in the PCL Profile.
https://msdn.microsoft.com/en-us/library/microsoft.windowsazure.storage.table.itableentity.aspx
Seeing the source at a quick glance(https://github.com/Azure/azure-storage-net/blob/master/Lib/Common/Table/ITableEntity.cs)
I'm writing an iOS application in Swift, and I'm trying to figure out how to organize the project into separate modules. I'm using an MVVM architecture, and I want to make the Model, ViewModel, and View components separate Swift modules that make only subsets of themselves accessible to the modules that import them. The files in the View would import the ViewModel, and files in the ViewModel would import the Model. How can I accomplish this? Note that I'm not trying to create libraries that multiple applications can share. I'm just trying to enforce separation of components using modules.
EDIT: Maybe the question is, "What mechanism should I use to create modules aside from the one that comes with the initial iOS application project?"
One of the answers in "How do you use Namespaces in Swift?" https://stackoverflow.com/a/24032860/215400 says, "classes (etc) are implicitly scoped by the module (Xcode target) they are in." From that, one might conclude that targets correspond to modules and that the answer is to create separate targets within an Xcode project, but I tried that earlier, and tskulbru is saying that I need multiple Xcode projects.
Regarding multiple Xcode projects, the File > New > Project > iOS Framework & Library > Cocoa Touch Framework option didn't look right because it's supposed to be for things that use UIKit, and two of the modules I want to create shouldn't depend on UIKit. The other "Framework & Library" option, Cocoa Touch static library, isn't an option with Swift.
Another StackOverflow post mentioned using private Pods. After spending an hour working on that, I concluded that it wasn't the right solution because I shouldn't have to edit these modules in different workspaces.
This isn't possible without creating separate projects for the modules you want to create. This is because the way Swift handles namespacing.
Eonil answered this better than me: https://stackoverflow.com/a/24032860/215400
(Copy below)
Answered by SevenTenEleven in the Apple dev forum:
Namespaces are not per-file; they're per-target (based on the
"Product Module Name" build setting). So you'd end up with something
like this:
import FrameworkA
import FrameworkB
FrameworkA.foo()
All Swift declarations are considered to be part of
some module, so even when you say "NSLog" (yes, it still exists)
you're getting what Swift thinks of as "Foundation.NSLog".
Also Chris Lattner tweeted about namespacing.
Namespacing is implicit in swift, all classes (etc) are implicitly
scoped by the module (Xcode target) they are in. no class prefixes
needed
From my perspective if you want to encapsulate your components, probably you have two solutions:
Framework
Internal cocoapods
Both solutions will give you fully encapsulated modules, where you can define API that will be available in project through public keyword.
All other things will be not visible in your core project.
Managing your project will cost you a lot more time, but if you write this using SOLID principles, probably you will get more reusable code and those frameworks could be imported to other project just using import definition.
My current code base involves writing console applications in C++ where I import a static library containing many common classes.
I would like to move to Swift and replicate this process. However, I have come across a couple difficulties:
As it stands, one apparently cannot create static libraries in Swift.
As it stands, one apparently can not import a framework into a Swift console application.
Currently I have been experimenting with writing a single view application and importing Frameworks that way, but enough has gone wrong that I would really like to simplify that and stick with console applications.
Given that, so far it appears that my only option for code reuse is to keep Swift files in common directories and drag them as needed into the console application. Since these console applications are for my own use and I'm only interested in the data they generate (i.e. I don't actually give the program to a user) this is actually a workable solution. I was hoping, however, there might be something a bit cleaner.
Any other suggestions on what to do for code reuse for pure Swift console applications, and if so, how do I go about doing it?
You can create a standard Swift framework that contains your common classes, and then create a console application that lives in a bundle. This will allow you to copy the framework into the bundle's framework folder which your console application will have access to at run time.
You can find more details about this approach in Alsey Coleman Miller's article about using embedded frameworks in OS X command line applications.
The downside, of course, is that your console application now lives inside a bundle.
I have some Model code that requires some methods from the System.IO.Compression namespace. However it is not present when using a PCL that targets VSMonoTouch and MonoAndroid as well. I see that some stuff is TypeForwarded in the MvvmCross solution, though when creating a similar project I can't seem to find out how to use it.
I created a MonoAndroid library project and added a Forward.cs class with the following content:
using System.Runtime.CompilerServices;
[assembly: TypeForwardedTo(typeof(System.IO.Compression.CompressionMode))]
[assembly: TypeForwardedTo(typeof(System.IO.Compression.DeflateStream))]
[assembly: TypeForwardedTo(typeof(System.IO.Compression.GZipStream))]
I have set the namespace of the project to System.IO.Compression. Trying to add it as a reference to the PCL project I have with my Model code which contains ViewModels, Services and what not it of course says that it can only reference other PCL projects and assemblies.
I especially need GZipStream and I cannot seem to find out how to add it to my project, so the question is how do I do that?
PCL Extension route
How to do this by extending PCL... I'm not entirely sure! One of the PCL guys might be able to assist with that.
Plugin route
The way I'd go about this is by defining the functionality I want in an interface and wrapping the code in a plugin.
For example in Cheesebaron.Plugins.Gzip.dll you could create an interface like:
public interface IGZipStreamFactory
{
Stream Decompress(Stream binaryStream);
}
This interface would then get plugged inside a PCL library that just contained this interface and the pluginmanager class.
Your PCL Core project can then reference this PCL plugin library and your ViewModel can use code like:
Cheesebaron.Plugins.GZip.PluginLoader.Instance.EnsureLoaded();
followed by
var service = this.GetService<IGZipStreamFactory>();
var unzipped = service.Decompress(inputStream);
For each actual platform implementation, you then prepare a platform specific library, you implement the GZip factory interface, and you provide a simple Plugin class implementation.
For example, for Droid you might create Cheesebaron.Plugins.Gzip.Droid.dll:
public class MyDroidGZipStreamFactory : IGZipStreamFactory
{
// the implementation
}
And you'd then add:
public class Plugin
: IMvxPlugin
, IMvxServiceProducer
{
public void Load()
{
this.RegisterServiceInstance<IGZipStreamFactory>(new MyDroidGZipStreamFactory));
}
}
Finally... to pull it all together, for MonoDroid you then reference both the PCL and the platform specific implementation in your UI project - and it should all work!
Note that there is a little convention based magic going on behind the scenes here - the framework loads the Assembly Cheesebaron.Plugins.Gzip.Droid.dll based on the PCL Plugin namespace being Cheesebaron.Plugins.Gzip
(For WP7 and other platforms, there's one additional step - there's a setup method to override which registers the plugin)
Note you can register as many services as you want to inside a single PlugIn, and you can perform extra common initialization/setup code too. This can help to reduce some project maintenance overhead: you can put your CheeseBaron IoC objects inside one single CheeseBaron.Plugins.Utils project if you like and then share just this one plugin across all your apps.
The DownloadCache Plugin provides a small sample of this - it registers all of IMvxHttpFileDownloader, IMvxImageCache and IMvxLocalFileImageLoader.
The downside with doing this is: eventual linked exe size - you're potentially adding unneeded code to each app.
Obviously this plugin approach has a little bit of a learning curve... and it does add a little project maintenance - but the good news is that these plugins can be used over and over again between projects - and can be shared between organisations (at least, that's my hope!)
More on creating plugins at:
MvvmCross vnext: merge plugins with monodroid
http://slodge.blogspot.co.uk/2012/06/mvvm-mvvmcross-monodroid-monotouch-wp7.html
For examples of plugins (not all available on all platforms), see https://github.com/slodge/MvvmCross/tree/vnext/Cirrious/Plugins
Other routes
If you don't want to use Plugins - e.g. if you are ever in a hurry or if you are writing code for a module that you don't want to reuse, then there are alternatives:
You can define an interface like IGZipStreamFactory in your share Core PCL library. You can then provide a platform specific implementation of this interface within each UI project, and can then use normal IoC/DI in the ViewModel/Model/Service layer in order to locate the correct implementation at runtime.
Or...
You can just dump the shared PCL core library and create separate platform-specific DLLs into which you then manually link in platform-specific files (I try never to do this, but others like it)
I'm getting a bit more seasoned with my iPhone development but I still don't know everything. One thing that bugs the hell out of me is having to add properties to a class, because there are four steps involved:
Add a class member to the Header file
Add the property definition to the Header file
Add a synthesize declaration to the implementation file
Add a release statement to the dealloc method in the implementation file
Is there any easier way to do it? A hidden feature of XCode I don't know about? A tool of some kind maybe?
Accessorizer might be what you're looking for. I've never used it personally but many Mac Developer podcasts give it rave reviews.