Installing dependencies using Swift Package Manager

Important: Swift Package Manager does not work with iOS apps!

Feel free to skip this and move onto the Setup discussion.

Most of my days are spent in the wonderful world of .Net, Visual Studio, and the almighty Nuget Package Manager which is the C# no-hassle/couldn't-be-easier-to-use dependency manager. I'm emphasizing this for a reason. There's no silver bullet, any-dummy-could-do-it way of managing dependencies in Xcode.

Today I decided that I'd like to check out RxSwift for a side project I'm starting and I decided to use Apples own Swift Package Manager to manage my dependencies. I mean, its the future of dependency management, right? Maybe? In my opinion, SPM honestly needs a GUI interface like Nuget Package Manager to become widely adopted.... but that's neither here nor there.

Anyway, let's get to the point of this article... installing dependencies using Swift Package Manager.

Setup

Don't skip over this. I did and I wasted two hours because I made the assumption that by having Xcode installed that my tooling was properly setup, it wasn't.

Install the Swift toolchain from https://swift.org/download/, here's the direct download link if you're super lazy like me.

Double-check that your Toolchains are indeed installed at `/Library/Developer/Toolchains`

installed.png

Open terminal and execute the following command:

    
    $ export TOOLCHAINS=swift
    

Sweet, now we're ready to rock.

Installing our dependency into a new project

This may not apply to many of us, so I'll cover installing into an existing project below. But, to install into a new project you create a new folder with your would-be projects name. Then navigate to the folder using Terminal. Let's assume I created a folder called `MyExampleProject` on my desktop. We'd navigate to the folder by typing this into Terminal:

    
$ cd Desktop/MyExampleProject/

Next we'll init our project using the following command.

    
$ swift package init
	

If all has gone well, your new folder should look like this:

Screen Shot 2018-02-03 at 3.09.01 PM.png

Now, let's open up our Package.swift file to see what we've got.

    
// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "MyExampleProject",
    products: [
        // Products define the executables and libraries produced by a package, and make them visible to other packages.
        .library(
            name: "MyExampleProject",
            targets: ["MyExampleProject"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages which this package depends on.
        .target(
            name: "MyExampleProject",
            dependencies: []),
        .testTarget(
            name: "MyExampleProjectTests",
            dependencies: ["MyExampleProject"]),
    ]
)

In order to import the RxSwift package, we'll need to add a dependency line item, which will look something like this:

    
dependencies: [
    .package(url: "https://github.com/ReactiveX/RxSwift.git", .exact("4.1.1")),
],

The code above just points to the GitHub url and specifies exactly which version of the library we want. There's a couple of overloads for this package method available. You can take a look at the source code here to see your other options.

Next, we'll update the targets section so that we're targeting our project correctly.

    
targets: [
    .target(
        name: "MyExampleProject",
        dependencies: ["RxSwift", "RxCocoa"])
]

So, here we're targeting our project and defining dependencies of RxSwift and RxCocoa, which we're importing in the dependencies section.  

So here's what the final code should look like:

    
import PackageDescription

let package = Package(
    name: "MyExampleProject",
    products: [ 
        .library(
            name: "MyExampleProject",
            targets: ["MyExampleProject"]),
    ],
    dependencies: [
        .package(url: "https://github.com/ReactiveX/RxSwift.git", .exact("4.1.1")),
    ],
    targets: [
        .target(
            name: "MyExampleProject",
            dependencies: ["RxSwift", "RxCocoa"])
    ]
) 

Next, we'll just execute the following command:

    
$ swift package generate-xcodeproj

This process fetches all of the specified packages listed, installs them and generates an Xcode project. Your folder should now look like this:

If you open your project and build it, you should see a Dependencies folder with your dependencies, and you should also be able to access your dependencies without a problem.

rxswiftinstalled

Installing a Swift Package into an existing project

Alright, Just to be safe you should check all of your code into source control or make sure you have a backup of your project.

So, your project may look something like this:

Screen Shot 2018-02-03 at 3.34.47 PM.png

We'll navigate to the project using Terminal, just as before. Look up above for code reference.

Once we're at our folder location that contains our project, we'll execute the following command to initialize our Swift Package Manager for this project.

    
$ swift package init

Your directory should now look something like this:

Screen Shot 2018-02-03 at 3.36.04 PM.png

Next, just as before, we'll update our Package.swift file to point to our desired dependency, in this example, once again, we'll pull in RxSwift.

    
import PackageDescription

let package = Package(
    name: "MyExistingProject",
    products: [
        .library(
            name: "MyExistingProject",
            targets: ["MyExistingProject"]),
        ],
    dependencies: [
        .package(url: "https://github.com/ReactiveX/RxSwift.git", .exact("4.1.1")),
        ],
    targets: [
        .target(
            name: "MyExistingProject",
            dependencies: ["RxSwift", "RxCocoa"])
    ]
)

note that this file has changed slightly to accommodate our project name.

So, here's where I'm a bit unsure of the best way to do this so if you have any suggestions you get bonus points for correcting me here. My intuition says that we can use the command swift build to simply build our packages. However, this doesn't actually add RxSwift to our applications. By experimenting, I was able to get the RxSwift projects loaded by using the same swift package generate-xcodeproj command. So, yeah, back up your project files.

With that said, we'll once again execute the following command:

    
$ swift package generate-xcodeproj

Which, for me, installed the RxSwift project files into my project for me. My existing project now looks like this:

Screen Shot 2018-02-03 at 3.54.06 PM.png

The last thing you'll need to do is edit click ManageScheme in the top left and add your app scheme back into the project.  

Feel free to ask questions or offer corrections in the comments below. Thanks to @vzsg in the RxSwift Slack Community for his guidance.

How to add Microsoft's Azure Services to your Swift apps

Let’s see how to integrate an Azure service into your Swift application in Xcode. What I’m about to show you will work with any of Azure’s iOS libraries since they are all written in Objective-C. 

Just head over to Microsoft’s GitHub repo’s and download the service library you need.

In this tutorial, we’ll install Azure Storage Client Library for blob storage. 

Now, there are a couple of ways to install these libraries. You can use CocoaPods, which if you’re using the same point release of Xcode that the library was created with you should be alright, otherwise, you’re sure to be in for an untold quantity of build errors before you’re up and running. Alternatively, you could install the service as a framework provided it was compiled correctly for your current Xcode version. Or, you can do it the fool-proof way, and just include the Objective-C files into your application and add a bridging header. 

(Dear Apple, please see Nuget Package Manager…)

This is my preferred approach because it's timeless. Doesn’t matter which version of Swift you are using or what version of Xcode you’re using. It just works.

So, assuming you’ve got an existing Xcode project and the Azure service you wish to install downloaded to your computer. We can get started.

In the downloaded folder, look for the Objective-C source code. In the case of Azure Storage Client Library, its a folder named after the service. So, find something like this:

1folder.png

Next, create a new Group in your Xcode project and name it whatever you like. I just named mine “Azure Storage”. Once you have the folder created, go ahead and drag all of the Objective-C files from the folder you downloaded to your new Xcode project folder. Select copy if needed and then “Finish”.

Xcode will then ask you if you want to create a bridging header for these Objective-C files, select “Create Bridging Header”, we’ll need this bridging header to expose Azure to our Swift code.

2bridgingheader.png

By default, Xcode will place that bridging header in with off of Azure’s Objective-C files, I personally move this file into my own project hierarchy since I might reuse this file to incorporate other Objective-C libraries.

If we choose to move it, we’ll need to inform Xcode where we moved it to. We can update our bridging header path by editing the location stored under Objective-C Bridging Header in our Build Settings

Since I moved my bridging header into the main project hierarchy, I had to update my path to “AzureStorageExample/AzureStorageExample-Bridging-Header.h”

3buildsettings.png

Once we have that updated, Xcode will, once again, be able to expose Azure’s Objective C code to our Swift code. Of course, this wouldn’t be a day in the life of an Xcode user if there wasn’t a follow-up error.

4filenotfound.png

Looks like Azure has a dependency on `libxml/xmlwriter.h`, which is pretty simple to resolve. We’ll just have to tell Xcode where the file is. 

We’ll go back into our build settings and select “All” and then “Levels” from our build settings and then search for “Search Paths”. Under header search paths, we’ll add a search path of “${SDKROOT}/usr/include/libxml2”.

If we rebuild we’ll get a gang of errors. We’ve got one last step here.

Go to build phases > link library with binaries and add libxml2.tbd to your project.

6libxml2.png

Rebuilding now should result in a successful deployment.

7proof.png

If you run into any issues you can download the example project from GitHub here. You can also feel free to comment below and I'll do my best to help.

 

A cleaner SWRevealViewController implementation using Swift extensions

Extensions allow us to extend the functionality of the native Swift language with our own functionality.

I'd like to provide a real-world example where extending a specific type really reduces clutter in my applications. I often use the popular SWRevealViewController library to add a neat sidebar menu to my applications. Once I have the application setup, I have to run the following block of code in my viewDidLoad:

    
override func viewDidLoad() {
    super.viewDidLoad()
        
    if self.revealViewController() != nil {
        self.menuButton.target = self.revealViewController()
        self.menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
        self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
        self.revealViewController().rearViewRevealWidth = 200
    }
}

I have to add this exact block of code in every single ViewController or TableViewController that implements SWRevealViewController. This leads to unnecessary clutter and repetition...

Rule of thumb

In programming, when you find yourself repeating something consistently, there's probably a better way to do it.

 

So we write an extension to UIViewController, and since UITableViewController inherits from UIViewController, we cover our table view's as well.

    
extension UIViewController {
    func setupRevealMenu(controller : UIViewController) {
        if self.revealViewController() != nil {
            controller.menuButton.target = self.revealViewController()
            controller.menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
         self.view.addGestureRecognizer(controller.revealViewController().panGestureRecognizer())
            self.revealViewController().rearViewRevealWidth = 200
        }
    }
}

This actually gives us an error, because not every View Controller and Table View Controller use an SWRevealViewController, so that menuButton doesn't always exist! We need to constrain our extension to just those that actually derive from SWRevealViewController. In order to make this constraint possible, we need to define a protocol that will act as a contract or guarantee that our menuButton will indeed exist.

    
protocol Revealable {
    weak var menuButton: UIBarButtonItem! { get set }
}

Now that we have that guarantee, we just need to add this Revealable protocol to every single Controller that uses an SWRevealViewController.

    
class HomeTableViewController: UITableViewController, Revealable {/* ... */ }

Now, we just update our extension with our new constraint.

    
extension UIViewController { 
    func setupRevealMenu<T : UIViewController where T : Revealable>(controller : T) { 
        if self.revealViewController() != nil { 
            controller.menuButton.target = self.revealViewController() 
            controller.menuButton.action = #selector(SWRevealViewController.revealToggle(_:)) 
            self.view.addGestureRecognizer(controller.revealViewController().panGestureRecognizer()) 
            self.revealViewController().rearViewRevealWidth = 200 
        } 
    } 
}

The code below adds the button programmatically.

    
protocol Revealable : class {}

extension Revealable where Self: UIViewController {
    func setupRevealMenu() { 
        if self.revealViewController() != nil {
            let button = UIButton.init(type: .custom)
            button.setImage(UIImage.init(named: "box-trans.png"), for: UIControlState.normal)
            button.addTarget(self.revealViewController(), action:#selector(SWRevealViewController.revealToggle(_:)), for: UIControlEvents.touchUpInside)
            button.frame = CGRect.init(x: 0, y: 0, width: 30, height: 30)
            let barButton = UIBarButtonItem.init(customView: button)
            
            self.navigationItem.leftBarButtonItem = barButton
            self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
            self.revealViewController().rearViewRevealWidth = 200
            self.revealViewController().panGestureRecognizer().isEnabled = false
        }
    }
}

If you have any questions, please feel free to ask in the comments!

Resources

Setting up your first ReactiveUI Project with Xamarin Forms

In this tutorial we go through the process of installing and setting up ReactiveUI 7 in Xamarin using the Model-View-View-Model pattern. Here, we'll take a high level look at all of the moving pieces we need in order to end up with an app that binds using ReactiveUI.

Installing ReactiveUI

We’ll begin by opening Visual Studio (or Xamarin studio) for mac. We’ll select `File->New Solution` and we’ll select Forms App. Click Next. Choose a name, we’ll target both Android and iOS, choose portable class library and I personally write my interfaces using C# but you can use XAML if that’s what you are comfortable with. We’ll move on to the next dialog and if we’re happy with were Visual Studio is saving our project, we’ll click create.

Once Visual Studio has finished loading our project we’ll go ahead and add our ReactiveUI packages.

Expand your Xamarin forms project and right click on packages and select `Add Packages…` Once the package manager dialog appears, search for RectiveUI, select the version you want to work with and click Add Packages. Accept the subsequent agreements and your packages should install without a problem. Next, go ahead and install the reactiveui-xamforms package. 

Once complete, double check that your packages look like this:

Screen Shot 2017-05-24 at 9.00.44 PM.png

Noticed that the package manager has automatically added the Rx and Splat dependences along with reactiveui and reactiveui-core.

Next, we’ll go ahead and add ReactiveUI to both our .Droid and .iOS projects as well. These steps are the same as with the forms project.

Just make sure that all of your package versions are exactly the same.

ReactiveUI Base Classes

Now that we have ReactiveUI installed we’ll set up our project using the MVVM pattern.

We’ll begin by adding two folders to our Xamarin Forms application. We’ll create a folder for our ContentPages, which we’ll call UserInterfaces and one for our ViewModels which we’ll call ViewModels. Once complete, your solution should look something like this.

Screen Shot 2017-05-24 at 9.21.42 PM.png

Next, we’ll add a pair of base classes. While this step isn’t necessary to use ReactiveUI, it does enforce a predictable pattern across our documents making them easier to work with over time.

We’ll start by right clicking on our ViewModels and we’ll select add file. We’ll create a new C# file which we’ll name ViewModelBase. Next we’ll add the following code.

    
// 1
public abstract class ViewModelBase : ReactiveObject, IDisposable where T : ReactiveObject, IDisposable 
{
    // 2
    protected readonly Lazy ViewModelBindings = new Lazy(() => new CompositeDisposable());
    // 3
    public bool IsDisposed { get; private set; }
    // 4
    protected abstract void RegisterObservables();
    // 5
    protected ViewModelBase()
    {
        RegisterObservables();
    }
    // 6
    #region IDisposable implementation
    public void Dispose()
    {
        if (!IsDisposed)
        {
            IsDisposed = true;
            Dispose(true);
            GC.SuppressFinalize(true);
        }
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)

        if (ViewModelBindings != null)
        {
            ViewModelBindings.Value.Dispose();
        }
    }

    #endregion
} 

This is a minimal version of a ViewModelBase class implementation that I learned from the mobile development experts at Eight Bot. This version, of course, is drastically stripped down compared to what one might use in production. But it will get us up and running for this exercise.

Let's take a high level look at what's going on here.

  1. We have an abstract class named ViewModelBase that offered a generic parameter. In ReactiveUI, all view model base classes must inherit from ReactiveObject, we are also implementing IDisposable. Finally, we're explicitly stating that our generic `T` parameter must implement both ReactiveObject and IDisposable.
  2. We’ve created a Lazy CompositeDisposable named ViewModelBindings. We’ll use this property to collect our ViewModels disposable subscriptions which get cleared out when our pages Dispose override method gets called. To learn more about CompositeDisposable check out the Introduction to Rx page on Disposables.
  3. We’re employing a boolean flag named IsDisposed to keep track of whether our objects have been disposed. This will keep us safe from disposing of an object more than once.
  4. RegisterObservables is an abstract method that we'll use to register our observables in our view model.
  5. Our class constructor which, in this simple example, simply calls our RegisterObservables method.
  6. Finally we take care of our disposables. This should be familiar to those who have spent any time using .Net. You can learn more about IDisposable here[3]

That does it for our ViewModelBase class. Once again, this is a simple version of what one might use in production but it is by no means production ready. Let’s go ahead and wire up a ContentPage base class using ReactiveUI.

Right click on your UserInterfaces folder and add a new C# file named ContentPageBase. Next, we’ll add the following code to out new file.

    
// 1
public abstract class ContentPageBase : ReactiveContentPage where TViewModel : ViewModelBase 
{   
    // 2
    protected Lazy ControlBindings = new Lazy(() => new CompositeDisposable()); 

    // 3 
    protected abstract void SetupUserInterface();
    protected abstract void BindControls();

    // 4
    protected ContentPageBase() : base()
    {   
        SetupUserInterface(); 
        BindControls();  
    }

    // 5
    protected override void OnDisappearing()
    {
        base.OnDisappearing();  
        UnbindControls(); 
    }  

    protected void UnbindControls()
    {  
        if (ControlBindings == null) return; 
        ControlBindings.Value.Clear();
    } 
}

 

As with our ViewModelBase, this ContentPageBase is a simplified example of what you might use in production.

Let’s break this down line by line.

  1. First and foremost, we are inheriting from ReactiveUI’s generic ReactiveContentPage class, which takes a generic type which is of type ViewModelBase.
  2. Here we are defining a lazy CompositeDisposable. We’ll use this property to collect our disposable subscriptions which get cleared out when our pages OnDisappearing override method gets called.
  3. We we are defining two abstract methods. One that will run our user interface code, and another that will bind our user interface controls to our View Model properties.
  4. Here we have our constructor, which calls SetupUserInterface followed by BindControls
  5. Next we call Xamarin Forms’ OnDisappearing method where we’ll remove our ControlBindings.

ReactiveUI in Action

Now we have everything we need to wire up a simple interface. We’ll begin by adding a new class which we’ll name `Dashboard.cs` to our ViewModels folder. Once our document has loaded we’ll make sure that our namespace to reflect our folder hierarchy to avoid collisions.

 
    
namespace YourAppName.ViewModels

We’ll inherit from our newly created ViewModelBase class and simply pass our Dashboard class type in as our type specifier. At this point Visual Studio will require that we implement our abstract base class, which is what we’ll do.

Before we move on, I want to point out that the goal of this exercise it for you to get up and running with ReactiveUI and MVVM. So I’ll forgo any in-depth explanation of the moving pieces you’re about to see. If you have any questions feel free to leave them in the comments section below.

Let’s go ahead and add the rest of our Dashboard class now.

    
public class Dashboard : ViewModelBase
{ 
    // 1
    string _statusMessage;

    [DataMember]
    public string StatusMessage
    {
        get { return _statusMessage; }
        private set { this.RaiseAndSetIfChanged(ref _statusMessage, value); }
    }

    ImageSource _currentImage;

    [DataMember]
    public ImageSource CurrentImage
    {
        get { return _currentImage; }
        set { this.RaiseAndSetIfChanged(ref _currentImage, value); }
    }

    [DataMember]
    public List ImageList { get; set; } = new List();
 
    [DataMember]
    public string Title
    {
        get { return "My Dashboard"; }
    }
    // 2
    public ReactiveCommand InitializeCommand { get; private set; } 

    // 3
    protected override void RegisterObservables()
    {
        // 4
	InitializeCommand = ReactiveCommand.CreateFromTask(async _ => 
	{
	    // initialization logic goes here 
	    StatusMessage = "Initializing";

	    // maybe we're getting images from a server 
	    await Task.Delay(1000); // but we should really use Task.Delay in our apps right?

	    StatusMessage = "Downloading";

	    // simulate a lengthy server response
	    await Task.Delay(3000); 

	    StatusMessage = "Go-Go Random Logos!";

	    ImageList.Add("xamagon.png");
	    ImageList.Add("eightbot.png");
	    ImageList.Add("reactivelogo.png");
	    ImageList.Add("codebeaulieu.png");
	    ImageList.Add("Rx_Logo_512.png");

	    await Task.Delay(1000);
	    await Task.FromResult(Unit.Default);

        }).DisposeWith(ViewModelBindings.Value);

        // 5
	Observable
	    .Interval(TimeSpan.FromMilliseconds(500))
	    .ObserveOn(RxApp.MainThreadScheduler)
	    .Select(_ =>
	    {
	        if (ImageList.Count == 0) 
		    return ImageSource.FromFile("reactivelogo.png");

		Random random = new Random();
		int number = random.Next(0, ImageList.Count);

		return ImageSource.FromFile(ImageList[number]); 
					 
	    }).BindTo(this, x => x.CurrentImage);
     }
 }

We’ll take a high level look at whats going on but we’ll spare the detail.

  1. We’ve included several properties that we’ll bind to in our Dashboard ContentPage.
  2. We’re including a status message which is of type string, current image which is a Xamarin Forms ImageSource, a List of strings that will hold a list of image names and title which is of type string.
  3. We’re including a ReactiveCommand which we’ll bind to in our ContentPage later.
  4. Next we have our RegisterObservables method which, if you recall from our base class implementation, gets called from our constructor.
  5. Here we have our ReactiveCommand implementation. When our command gets fired from our ContentPage, this is the logic that will execute.
  6. Finally, we have a Reactive observable that fires every have second and binds a random image to our CurrentImage property.
Important: In order for your application to run, you’ll need to add images to both your iOS and Droid projects respectful resource folders. If you are at a shortage of images, you can use the ones that I’ve included in this project by downloading them from my example project here.[4]

Alright, we’re almost there! Let’s finish up by adding a content page to our app. We’ll right click on our UserInterfaces folder and add another file named Dashboard.cs. Hopefully you remembered to change your namespace earlier or you’ll be sure to confuse the compiler.

The first thing we’ll do is inherit from our ContentPageBase and then we’ll pass in our view model dashboard type. The rest of the code for this demo, goes something like this:

    
public class Dashboard : ContentPageBase
{
    // 1
    Image _images;

    Label _status;

    //2
    public Dashboard()
    {
        ViewModel = new ViewModels.Dashboard(); 
    }

    //3
    protected override void SetupUserInterface()
    { 
        _status = new Label
        { 
            FontSize = 20,
	    FontFamily = Device.OnPlatform("AvenirNext-Medium", "Roboto", "Verdana"),
	    HorizontalTextAlignment = TextAlignment.Center,
	    VerticalTextAlignment = TextAlignment.Center,
	    HorizontalOptions = LayoutOptions.CenterAndExpand,
	    VerticalOptions = LayoutOptions.Center,
	    Margin = new Thickness(0,40,0,0)
        };

        _images = new Image {
	    HorizontalOptions = LayoutOptions.FillAndExpand,
	    VerticalOptions = LayoutOptions.FillAndExpand,
	    Aspect = Aspect.AspectFit, 
	    HeightRequest = 350 
        };

	Content = new StackLayout 
	{
	    HorizontalOptions = LayoutOptions.FillAndExpand,
	    VerticalOptions = LayoutOptions.FillAndExpand,
	    Padding = 20,
	    Children = { 
                _status,
		_images
	    }
        };
    }

    //4
    protected override void BindControls()
    {
        this.OneWayBind(ViewModel, vm => vm.Title, c => c.Title)
	    .DisposeWith(ControlBindings.Value);

	this.Bind(ViewModel, x => x.StatusMessage, c => c._status.Text)
            .DisposeWith(ControlBindings.Value);

        this.WhenAnyValue(x => x.ViewModel.CurrentImage)
            .BindTo(this, x => x._images.Source)
	    .DisposeWith(ControlBindings.Value);
        
        this.WhenAnyValue(x => x.ViewModel)
            .Where(x => x != null)
            .InvokeCommand(this, x => x.ViewModel.InitializeCommand)
            .DisposeWith(ControlBindings.Value);
            
    } 
}

Since the goal is to demonstrate the pattern, we’ll take a high level look at the rest of the implementation.

  1. Here we have our user interface controls. We’ll be binding to these in a moment.
  2. Here we have our class constructor. We’re setting our ViewModel equal to our ViewModels.Dashboard file. ViewModel belongs to the ReactiveUI framework.
  3. Next, we’re calling our InitializeCommand on our freshly set view model and calling execute. This will execute our logic in our InitializeCommand implementation.
    User interface setup, nothing interesting here.
  4. And here is where the magic happens… We’re using three different binding statements to bind our interface controls to observables in our view model.

So, your code should be complaining right now since DisposeWith doesn’t actually exist in ReactiveUI! This is an extension method provided by Eight Bot in their public GitHub repository on Reactive-Extension, which you can find here.

Create a new folder in your application named Extensions and add a new class named IObservableExtensions. Add the following code.

 
    
 /*
    This extension was taken from Eight Bot's Reactive-Exampes repository with permission.
    url: https://github.com/TheEightBot/Reactive-Examples/blob/master/ReactiveExtensionExamples/Extensions/IObservableExtensions.cs
    author: Mike Stonis
    website: http://www.eightbot.com/
*/
public static class IObservableExtensions
{
    public static TDisposable DisposeWith(this TDisposable observable, CompositeDisposable disposables) where TDisposable : class, IDisposable
    {
        if (observable != null)
            disposables.Add(observable);

	return observable;
    }
}
      

Thanks to Mike Stonis for sharing gems like this.

And with that, we are ready to run our application.

 

 

Download project files from GitHub

How to create a Combined Bar and Line chart using ios-charts

This tutorial is part of a series on iso-charts, if you haven't looked over the introduction I'd advise doing so before continuing. In this tutorial, we'll be making a combined chart using iOS-charts.

We’ll begin by creating a new single view application, we’ll name it and click create.

Go to the main.storyboard and search for “View” in the Object Library and you’ll see it near the bottom of the list. Drag the view out onto your view controller, position it however you like and add some basic constraints.

In the identity inspector, set the class for your new View to “CombinedChartView”, if you aren’t seeing an option for such a class please make sure you’ve followed the installation steps listed here.

If everything has gone well your main.storyboard should look like this:

one.png

 

Setting up our CombinedChartView object

Click on your Assistant Editor to reveal your ViewController.swift code. We’ll need to add an import statement and adopt a protocol before we can begin wiring up our Line Chart. Modify your class signature to look like this:

    
import Charts

class ViewController: UIViewController, ChartViewDelegate { //...

Now we can control drag from our View to our ViewController class and create an outlet named chartView with a type of CombinedChartView.

    
@IBOutlet weak var chartView: CombinedChartView!

We can now start setting the properties of our chartView object. For simplicity, we'll just set our chart properties in our  viewDidLoad, add the following lines of code:

    
override func viewDidLoad() {
    super.viewDidLoad()
    // 1    
    chartView.delegate = self
    // 2
    chartView.descriptionText = "Tap node for details" 
    // 3
    chartView.noDataTextDescription = "You need to provide data for the chart." 
    // 4
    chartView.drawBarShadowEnabled = false 
    // 5
    chartView.leftAxis.startAtZeroEnabled = false 
 
}

I should point out that not all of these options are necessary, I've just included them to expose you to more options.

  1. We set the ChartViewDelegate to our ViewController.
  2. We change the descriptionText that will appear at the bottom of our chart.
  3. Here, we are setting the "no data" description for when our chart's data source is empty.
  4. We're removing the bar shadow for a cleaner look.
  5. Disable "starting at zero" so that our charts start near the lowest data point.

Setting Data

In this dataset, we'll just utilize some random numbers. At the top of your ViewController add the following properties. 

    
var dataSet1 : [Double] = [123, 154, 132, 119, 134, 122, 126, 156, 143, 157, 163, 212] 
    var dataSet2 : [Double] = [132, 119, 139, 122, 126, 135, 145, 116, 123, 140, 135, 132] 
    var dataSet3 : [Double] = [112, 99, 102, 92, 96, 115, 105, 102, 99, 110, 115, 108] 
    let months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 

Then, add the following after the last line of code in your viewDidLoad:

    
// 6 
    let data: CombinedChartData = CombinedChartData(xVals: months) 
    data.lineData = self.setLineData()
    data.barData = self.setBarData()
    // 7
    chartView.data = data 
    // 8
    chartView.animate(xAxisDuration: 0.2, yAxisDuration: 1.0, easingOptionX: .EaseInExpo, easingOptionY: .EaseInExpo)
    
  1. Here we set up our CombinedChartData adding both lineData and bar Data.
  2. Add our data to the chartView.
  3. animate our chart.

Next, we'll define our two function  we used to set our lineData and our barData:

    
func setLineData() { }
func setBarData() { }

For this part of the tutorial, we'll set each chart up with two sets of data, which will create a single red line across our graph. I won't go into detail here because as you read through you'll get a good idea of what the properties mean.    

    
func setLineData(months : [String]) {
        var xVals: [ChartDataEntry] = [ChartDataEntry]()
        for i in 0 ..< months.count {
            xVals.append(ChartDataEntry(value: dataSet1[i], xIndex: i))
        }
        
        // 1 ////////////////
        var yVals: [ChartDataEntry] = [ChartDataEntry]()
        for i in 0 ..< months.count {
            yVals.append(ChartDataEntry(value: dataSet1[i], xIndex: i))
        }
        
        let set1: LineChartDataSet = LineChartDataSet(yVals: yVals, label: "Line set 1")
        set1.axisDependency = .Left
        set1.setColor(UIColor.redColor().colorWithAlphaComponent(0.5))
        set1.setCircleColor(UIColor.redColor())
        set1.lineWidth = 2.0
        set1.circleRadius = 6.0
        set1.fillAlpha = 65 / 255.0
        set1.fillColor = UIColor.redColor()
        set1.highlightColor = UIColor.whiteColor()
        set1.drawCircleHoleEnabled = true
        
        // 2 ////////////////
        var yVals2: [ChartDataEntry] = [ChartDataEntry]()
        for i in 0 ..< months.count { 
            let dataEntry: ChartDataEntry = ChartDataEntry(value: dataSet2[i] + 100, xIndex: i)
            yVals2.append(dataEntry)
        }
        let set2: LineChartDataSet = LineChartDataSet(yVals: yVals2, label: "Line set 2")
        set2.axisDependency = .Left
        set2.setColor(UIColor.greenColor().colorWithAlphaComponent(0.5))
        set2.setCircleColor(UIColor.greenColor())
        set2.lineWidth = 2.0
        set2.circleRadius = 6.0
        set2.fillAlpha = 65 / 255.0
        set2.fillColor = UIColor.greenColor()
        set2.highlightColor = UIColor.whiteColor()
        set2.drawCircleHoleEnabled = true
        
        // data sets
        var dataSets: [LineChartDataSet] = [LineChartDataSet]()
        dataSets.append(set1)
        dataSets.append(set2) 
        let data: LineChartData = LineChartData(xVals: months, dataSets: dataSets)
        
        data.setValueTextColor(UIColor.whiteColor())
        data.setValueFont(UIFont.systemFontOfSize(9))
        
        
        return data            
    }
    <>
    

Then we'll do the same for our barCharData function:

    
func setBarData() -> BarChartData {
        let d: BarChartData = BarChartData()
        
        var entries1: [ChartDataEntry] = [ChartDataEntry]()
        for index in 0 ..< months.count {
            entries1.append(BarChartDataEntry(value: Double(Int.random(25...45)) * 100, xIndex: index))
        }
        let set1: BarChartDataSet = BarChartDataSet(yVals: entries1, label: "Bar Data")
        set1.setColor(UIColor.darkGrayColor())
        set1.valueTextColor = UIColor.redColor()
        set1.valueFont = UIFont.systemFontOfSize(10)
        set1.axisDependency = .Right
        d.addDataSet(set1)
        
        var entries2: [ChartDataEntry] = [ChartDataEntry]()
        for index in 0 ..< months.count {
            entries2.append(BarChartDataEntry(value: Double(Int.random(25...45)) * 100, xIndex: index))
        }
        let set2: BarChartDataSet = BarChartDataSet(yVals: entries2, label: "Bar Data")
        set2.setColor(UIColor.blackColor())
        set2.valueTextColor = UIColor.redColor()
        set2.valueFont = UIFont.systemFontOfSize(10)
        set2.axisDependency = .Right
        d.addDataSet(set2)
        
        // data sets
        var dataSets: [BarChartDataSet] = [BarChartDataSet]()
        dataSets.append(set1)
        dataSets.append(set2)
        let data: BarChartData = BarChartData(xVals: months, dataSets: dataSets)
        
        data.setValueTextColor(UIColor.whiteColor())
        data.setValueFont(UIFont.systemFontOfSize(9))

        
        return data
    }
    

Build and run

Build and run and you should see your combinedChart in action!

 

In Tags

Adding multiple lines to your Line Chart using ios-charts

In part 1 we created a single line chart, in this tutorial we'll simply add 2 more data sets to our Line-Chart.

Multiple Lines

To add multiple lines you simply add multiple datasets like so:

    
let dollars1 = [1453.0,2352,5431,1442,5451,6486,1173,5678,9234,1345,9411,2212]
let dollars2 = [5641.0,2234,8763,4453,4548,6236,7321,3458,2139,399,1311,5612]
let dollars3 = [6541.0,3456,7843,5678,5877,7323,7111,6456,5143,4562,6311,10412]
    

Once you have your data sets you can simply repeat what we've did in our last tutorial to add additional lines:

    
func setChartData(months : [String]) {
        
    var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
    for var i = 0; i < months.count; i++ {
        yVals1.append(ChartDataEntry(value: dollars1[i], xIndex: i))
    }
        
    let set1: LineChartDataSet = LineChartDataSet(yVals: yVals1, label: "First Set")
    set1.axisDependency = .Left // Line will correlate with left axis values
    set1.setColor(UIColor.redColor().colorWithAlphaComponent(0.5))
    set1.setCircleColor(UIColor.redColor())
    set1.lineWidth = 2.0
    set1.circleRadius = 6.0
    set1.fillAlpha = 65 / 255.0
    set1.fillColor = UIColor.redColor()
    set1.highlightColor = UIColor.whiteColor()
    set1.drawCircleHoleEnabled = true
        
    var yVals2 : [ChartDataEntry] = [ChartDataEntry]()
    for var i = 0; i < months.count; i++ {
        yVals2.append(ChartDataEntry(value: dollars2[i], xIndex: i))
    }
        
    let set2: LineChartDataSet = LineChartDataSet(yVals: yVals2, label: "Second Set")
    set2.axisDependency = .Left // Line will correlate with left axis values
    set2.setColor(UIColor.greenColor().colorWithAlphaComponent(0.5))
    set2.setCircleColor(UIColor.greenColor())
    set2.lineWidth = 2.0
    set2.circleRadius = 6.0
    set2.fillAlpha = 65 / 255.0
    set2.fillColor = UIColor.greenColor()
    set2.highlightColor = UIColor.whiteColor()
    set2.drawCircleHoleEnabled = true
        
    var yVals3 : [ChartDataEntry] = [ChartDataEntry]()
    for var i = 0; i < months.count; i++ {
        yVals3.append(ChartDataEntry(value: dollars3[i], xIndex: i))
    }
        
    let set3: LineChartDataSet = LineChartDataSet(yVals: yVals3, label: "Second Set")
    set3.axisDependency = .Left // Line will correlate with left axis values
    set3.setColor(UIColor.blueColor().colorWithAlphaComponent(0.5))
    set3.setCircleColor(UIColor.blueColor())
    set3.lineWidth = 2.0
    set3.circleRadius = 6.0
    set3.fillAlpha = 65 / 255.0
    set3.fillColor = UIColor.blueColor()
    set3.highlightColor = UIColor.whiteColor()
    set3.drawCircleHoleEnabled = true
        
    //3 - create an array to store our LineChartDataSets
    var dataSets : [LineChartDataSet] = [LineChartDataSet]()
    dataSets.append(set1)
    dataSets.append(set2)
    dataSets.append(set3)
        
    //4 - pass our months in for our x-axis label value along with our dataSets
    let data: LineChartData = LineChartData(xVals: months, dataSets: dataSets)
    data.setValueTextColor(UIColor.whiteColor())
        
    //5 - finally set our data
    self.lineChartView.data = data
}

Build and run

You should now see multiple lines on your graph, if you're having an issue check out the project files.

In Tags

How to create a Line Chart using ios-charts

This tutorial is part of a series on iso-charts, if you haven't looked over the introduction I'd advise doing so before continuing. In this tutorial we'll be making a single line Line Chart using iOS-charts.

We’ll begin by creating a new single view application, we’ll name it and click create.

Go to the main.storyboard and search for “View” in the Object Library and you’ll see it near the bottom of the list. Drag the view out onto your view controller, position it however you like and add some basic constraints.

In the identity inspector, set your class to “LineChartView”, if you aren’t seeing an option for such a class please make sure you’ve followed the installation steps listed here.

If everything has gone well your main.storyboard should look like this:

20151018043029addLineChartView.png

Setting up our LineChartView object

Click on your Assistant Editor to reveal your ViewController.swift code. We’ll need to add an import statement and adopt a protocol before we can begin wiring up our Line Chart. Modify your class signature to look like this:

    
import Charts
class ViewController: UIViewController, ChartViewDelegate { //...
    

Now we can control drag from our View to our ViewController class and create an outlet named lineChartView with a type of LineChartView.

20151018043325Screenshot 2015-10-17 22.34.21.png
    
@IBOutlet weak var lineChartView: LineChartView!

We can now start setting the properties of our lineChartView object. in your viewDidLoad add the following lines of code:

    
override func viewDidLoad() {
    super.viewDidLoad()    
    // 1
    self.lineChartView.delegate = self
    // 2
    self.lineChartView.descriptionText = "Tap node for details"
    // 3
    self.lineChartView.descriptionTextColor = UIColor.whiteColor()
    self.lineChartView.gridBackgroundColor = UIColor.darkGrayColor()
    // 4
    self.lineChartView.noDataText = "No data provided"
    // 5
    setChartData(months)
        
}

func setChartData() {

}

  1. We set the ChartViewDelegate to our ViewController.
  2. We change the `descriptionText` that will appear at the bottom of our chart.
  3. Here, we set our description text color to white and our grid background color to dark grey.
  4. We make sure our user get feedback if there is not data provided.
  5. Finally, we call / create a custom function that will add data to our chart.

Setting Data

Of course, a very common thing to chart is money over time, and that what we’ll do in this example. So we’ll modify the signature of our setChartData method call to take an array of strings for our months.

    
setChartData(months) // in viewDidLoad
func setChartData(months : [String]) { }
	

And we’ll have to create an array of months as a class level object. While we’re at it, lets go ahead and add three variables that hold our month-to-month dollar amount.

    
let months = ["Jan" , "Feb", "Mar", "Apr", "May", "June", "July", "August", "Sept", "Oct", "Nov", "Dec"]
    
let dollars1 = [1453.0,2352,5431,1442,5451,6486,1173,5678,9234,1345,9411,2212]

For this part of the tutorial, we'll set our chart up with just one set of data, which will create a single red line across our graph. First the code, then the explanation.

    
func setChartData(months : [String]) {
    // 1 - creating an array of data entries
    var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
    for var i = 0; i < months.count; i++ {
        yVals1.append(ChartDataEntry(value: dollars1[i], xIndex: i))
    }
        
    // 2 - create a data set with our array
    let set1: LineChartDataSet = LineChartDataSet(yVals: yVals1, label: "First Set")
    set1.axisDependency = .Left // Line will correlate with left axis values
    set1.setColor(UIColor.redColor().colorWithAlphaComponent(0.5)) // our line's opacity is 50%
    set1.setCircleColor(UIColor.redColor()) // our circle will be dark red
    set1.lineWidth = 2.0 
    set1.circleRadius = 6.0 // the radius of the node circle
    set1.fillAlpha = 65 / 255.0
    set1.fillColor = UIColor.redColor()
    set1.highlightColor = UIColor.whiteColor()
    set1.drawCircleHoleEnabled = true
        
    //3 - create an array to store our LineChartDataSets
    var dataSets : [LineChartDataSet] = [LineChartDataSet]()
    dataSets.append(set1)
        
    //4 - pass our months in for our x-axis label value along with our dataSets
    let data: LineChartData = LineChartData(xVals: months, dataSets: dataSets)
    data.setValueTextColor(UIColor.whiteColor())
        
    //5 - finally set our data
    self.lineChartView.data = data            
}
  1. We start by creating an array of ChartDataEntry items, to which we'll create and append one item for every value stored in our dollars array.
  2. We create a LineChartDataSet that take our array as its first parameter and a label for its second, this dataset represents the line we'll be creating. We continue by setting the attributes that belong to this class object.
  3. Since we're ultimately on a path to create a multi-lined array, we'll create a data set array that will just hold our single set.
  4. Create a data object that takes our months and our single data set.
  5. Set it as our lineCharView objects data 

Build and run

Build and run and you should see your first chart, congratulations, it gets better from here so move on to part II, where we augment this chart with multiple lines.

20151018050325Screen Shot 2015-10-18 at 12.02.56 AM.png

How to create beautiful iOS-charts by example

68747470733a2f2f7261772e6769746875622e636f6d2f64616e69656c67696e64692f696f732d6368617274732f6d61737465722f4173736574732f666561747572655f677261706869632e706e67.png

Welcome to an 8-part series on iOS-charts. ios-charts is a charting library by Daniel Cohen Gindi that was inspired by Philip Jahoda's Android charting library named MPAndroidChart.

In this series I'll introduce you to each of the 8 different types of charts you can make using iso-charts. Before we get started we'll need to install cocoa pods and install the iso-charts library. 

Below are the available and upcoming tutorials, if you'd like to request a tutorial, please do so in the comments below.

If you don't have iOS Charts installed in your application yet, you can follow this quick installation guide video.

 Installation Video Guide

  1. Line Chart
  2. Bar Chart (upcoming)
  3. Bubble Chart (upcoming)
  4. Candle Stick Chart (upcoming)
  5. Combined Chart
  6. Pie Chart
    • Pie Chart (in progress! example files ready)
  7. Radar Chart (upcoming)
  8. Scatter Chart (upcoming)

 

Passing data with the protocol delegate pattern

Delegates are the standard way we pass data between two view controllers. I recently wrote a tutorial on how to pass data by overriding prepareForSegue. In this tutorial I’ll show you how to pass messages back and forth using the “Standard” protocol pattern and without using any segues.

There won’t be an in-depth discussion about protocols or delegates here, for that I defer to Apples Swift Programming Language Guide or one of the many excellent books or online resources that have already covered this topic ad nauseam. 

What I will do, is create a succinct-minimal-working delegate pattern example, using naming conventions that will make it clear how the delegate pattern works. 

Setting Up

We’ll start by creating a single view application.

We’ll add a second View Controller to our storyboard which we’ll need to create a new CocoaTouch file for.  We’ll do that by clicking add new > cocoa touch class >  find UITableViewController… name it PresentedTableViewController and create. 

This controller class will belong to our “presented” view controller, so make sure you add it in your storyboard. Your final storyboard should look like this:

In the first View Controller, lets add a button and a label. We don’t need anything fancy for this exercise, just slap em out there. With split view open, control drag an outlet from your label and name it labelOutlet, and control drag an action from your button and name it doPresent. You should now have something like this:

    
class ViewController: UIViewController {
    
    @IBOutlet weak var textOutlet: UILabel!
    @IBAction func doPresent(sender: AnyObject) {

    }
    
    override func viewDidLoad() {
        super.viewDidLoad()   
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

With an interface that looks like this.

Now, select the other View Controller, the PresentedViewController and add a Text Field and a Button to the View. Just as before, control drag from your Text Field and create an outlet named “textFieldOutlet” and repeat that for your button, this time making an action named “doDismiss”. Your code should look like this:

    
class PresentedViewController: UIViewController {
   
    @IBOutlet weak var textFieldOutlet: UITextField!
    @IBAction func doDismiss(sender: AnyObject) {

    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

And your interface should resemble mine:

Protocol

The Standard pattern is to add our protocol to top of our “presented” class, though I’ve seen people create separate files for these too. We’ll do it the standard way here.

At the top of your PresentedViewController class, just above your class declaration we’ll add the following code.

    
protocol PresentedViewControllerDelegate {
    func acceptData(data: AnyObject!)
}

The convention is to adopt the presented classes name with “Delegate” afterwords. Inside our protocol we’ve defined one function, acceptData that takes AnyObject. I should note that we can define any number of functions and properties inside of our protocol, but no logic. 

Think of a protocol as a binding contract between the protocol and any class that implements it. This contract forces said classes to abide by it's "protocol" and in doing so creates a level of "trust" from the compiler. This "trust" enables us to communicate between two separate bodies of code.

PresentedViewController

We’ll add the required code necessary to receive data from the view controller, but this wont be a one way dialogue. We’ll wire this up so it will send data back to the View Controller as well.

At the class level, add two properties. One being a variable called delegate with a type PresentedViewControllerDellegate. Which will look like this:

    
// create a variable that will recieve / send messages
// between the view controllers.
var delegate : PresentedViewControllerDelegate?
// another data outlet
var data : AnyObject?

We’ll add a print statement in our viewDidLoad that will receive our “data” object from the ViewController. 

    
 override func viewDidLoad() {
    super.viewDidLoad()
    print("\(data!)")

}

Now, we’ll handle our Text Field and Button by adding the following lines of code inside the doDismiss method:

    
@IBAction func doDismiss(sender: AnyObject) {
    if textFieldOutlet.text != "" {
        self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
    }
}

You’ll notice that I’ve added a simple check to validate that the text field has content before we call presentingViewController!.disissViewControllerAnimated.

Finally, we’ll add viewWillDisappear which will  send our Text Field data to our delegates acceptData method. 

    
override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    if self.isBeingDismissed() {
        self.delegate?.acceptData(textFieldOutlet.text)
    }
}

Back in our ViewController, we’ll add PresentedViewControllerDelegate to our class signature like this:

    
class ViewController: UIViewController, PresentedViewControllerDelegate {//...

We’ll proceed with our protocol implementation by adding its acceptData(data:AnyObject!) method, which silences the compiler. Inside that method we’ll simply update our text label with the message we entered in PresentedViewController.

    
func acceptData(data: AnyObject!) {
    self.textOutlet.text = "\(data!)"
}

Finally, we’ll address the doPresent action we created earlier. Since in this exercise we aren’t passing values via Segue, we’ll need a method of traversing our data. In this case, it’s by presenting the view controller. We’ll create an instance of our PresentedViewController and with that instance, we can bind to it properties before presenting. That code looks like this:

    
@IBAction func doPresent(sender: AnyObject) {
    let pvc = storyboard?.instantiateViewControllerWithIdentifier("PresentedViewController") as! PresentedViewController
    pvc.data = "important data sent via delegate!"
    pvc.delegate = self
    self.presentViewController(pvc, animated: true, completion: nil)
}

Build And Run

When click the next button you should see the next view controller along with a print line in your console. If you enter some text in the text field and hit your go back button, you’ll see the text you entered assigned to you label.

If you have any troubles, feel free to download the Project Files and browse my code. You can also ask questions in the comments and we’ll get your code running.

Passing values using prepareForSegue

Set Up

The first thing we'll do is create a new single view application. Once the project is loaded, delete your ViewController.swift from your Project Manager as well as from your Storyboard.

Once you have this find a Navigation Controller in your object library and drag it out onto your storyboard, select your Navigation Controller in your StoryBoard and choose "Is Initial View Controller" in your Attributes Inspector. Now that you've got your initial view controller set up let's add a new Cocoa class to your project by right-clicking your main project folder in Project Manager and selecting "New File...". Select, iOS > Source > Cocoa Touch Class and then select next. Create a UITableViewController like I've done here.

We'll assign this new class as our table view in our storyboard by selecting our table view and adding our newly created class in our Identity Inspector it'll look like this.

Before we move on, click on your prototype cell in your storyboard and give it an Identifier of "Cell" and give it a Style of Basic for this example.

Now that we have our main controller lets add a View Controller that we'll send our values to. Drag a View Controller our onto your storyboard just as we did for our Navigation Controller. And just as we did with our FirstTableViewController, we'll add another Cocoa Touch Class, this time uses a UIViewController and we'll name it SecondViewController. Remember to add your new class to your View Controller in your storyboard as we did before for our FirstViewController.

Finally, we'll create a segue by control dragging from our FirstTableViewController to our SecondViewController like so.

Click on your new segue and in your Attributes Inspector add an Identifier, I chose "SendDataSegue" for this example.

We'll also want to add a label to our new View Controller, place it dead center and give it some simple constraints. Finally, create an outlet in your SecondViewController.swift by control dragging from your outlet to your class. 

Name your outlet viaSegueLabel, it should look like this:

@IBOutlet weak var viaSegueLabel: UILabel!

Code

Open your SecondViewController and at the class level, add a property called viaSegue like this:

var viaSegue = ""

Then inside your view controller we'll assign the value of viaSegue to our viaSegueLabel, add the following code to your viewDidLoad:

override func viewDidLoad() {
        super.viewDidLoad()

        viaSegueLabel.text = viaSegue
        // Do any additional setup after loading the view.
    }

We're finished with our viewController, lets move on to our tableViewController.

In our FirstTableViewController lets first quickly set our numberOfSectionsInTableView to 1 and numberOfRowsInSection to 10, I won't go into any detail here:

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return 10
    }

Now, let's add a method called prepareForSegue, which does exactly what it sounds like it does, it prepares for the upcoming segues.  To learn more about prepareForSegue see Apples Developer Guide. Here's the implementation:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "SendDataSegue" {
            if let destination = segue.destinationViewController as? SecondViewController {
                
                let path = tableView.indexPathForSelectedRow
                let cell = tableView.cellForRowAtIndexPath(path!)
                destination.viaSegue = (cell?.textLabel?.text!)! 
            }
        }
    }

In this method, we're determining which segue we're preparing for with segue.identifier, we're then using an if let to safely attempt to assign a segue with a destinationViewController with a type of ours. Getting the type lets us model the properties within, thus giving us access to our viaSegue in our SecondViewController, which we take advantage of here.

We haven't actually set up a segue yet, we'll do that now. Lets add a new tableView override function for didSelectRowAtIndexPath, this will allow us to trigger a segue from whichever row we select. The implementation is simple so I'll stop rambling.

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        _ = tableView.indexPathForSelectedRow!
        if let _ = tableView.cellForRowAtIndexPath(indexPath) {
            self.performSegueWithIdentifier("SendDataSegue", sender: self)
        }
        
    }

It's important to note that we are using our segue by it's identifier "SendDataSegue".

Last but not least, lets make sure our cells have some data to pass. Since we used the Basic setup for our prototype cell earlier, we've got access to a textLabel by default, so lets use it:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
        
        // Configure the cell...
        cell.textLabel?.text = "Hello from cell #\(indexPath.row))"
        
        return cell
    }

Build and Run

If everything as gone according to my master plan, you should've passed the value you selected. If you're having problems drop a line below or check out the project files.

Installing CocoaPods

What is CocoaPods?

"CocoaPods manages library dependencies for your Xcode projects.

The dependencies for your projects are specified in a single text file called a Podfile. CocoaPods will resolve dependencies between libraries, fetch the resulting source code, then link it together in an Xcode workspace to build your project.

Ultimately the goal is to improve discoverability of, and engagement in, third party open-source libraries by creating a more centralised ecosystem."

source

Installing cocoa pods

In terminal use the following two commands:

sudo gem install cocoapods
pod setup

If you're using El Capitan and experiencing issues try this:

sudo gem install -n /usr/local/bin cocoapods
pod setup
In Tags

How to add dynamic meta tags to your asp.net mvc views

Setting Up

We'll start by creating a new ASP.NET MVC 5 project and we'll make sure we have individual accounts selected. We're doing this so that we get entity framework and our dbcontext out-of-the-box. 

94f32fe3-cd15-473a-8872-884f09f545f1newProjectIndividualAccountsSelected.PNG

In your new project, let's create two models. We'll make a Page model and a MetaViewModel. The Page model will contain all of the properties that we'll be using in our database, the MetaViewModel will be used to shape the data for rendering our partial view. This will make perfect sense when you see it in context.

Adding Models

So let's create our Page.cs file in our model's folder and then we'll add the following code:

 
    
public class Page
{
    public int Id { get; set; }
    public string Author { get; set; }
    public string Keywords { get; set; }
    public string Description { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
}

and we'll go ahead an add our MetaViewModel as well in the same manor, here's the code:

    
public class MetaViewModel
{
    public string Author { get; set; }
    public string Keywords { get; set; }
    public string Description { get; set; }
}

Let's continue by adding our Page class to our dbcontext by creating a new property for it in our IdentityModels file (in your model folder). We're just going to add one line, like so:

    
public class ApplicationDbContext : IdentityDbContext
{
    public ApplicationDbContext() 
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    public DbSet Pages { get; set; } // this is the line we're adding
}

Build your project but don't actually run it yet.

Controller Logic

Now that we've built our project the compiler knows about our new models for sure. Let's add a controller by right-clicking on the controller folder and selecting add > controller.

We'll choose to create an "MVC 5 Controller with views using Entity Framework", you'll see a form appear add the following constraints: 

071552d9-9f98-4712-a71a-45d9c1f73879createPagesController.PNG

We'll put our MetaViewModel to use in our new PagesController, add the following Action Result to your controller.

    
public ActionResult ListMeta(int? id = 1)
{
    var post = db.Pages.Find(id);

    MetaViewModel meta = new MetaViewModel();
    meta.Author = post.Author;
    meta.Keywords = post.Keywords;
    meta.Description = post.Description;

    return PartialView("~/Views/Pages/_ListMeta.cshtml", meta);
}

We'll need a Partial View

Notice that we're returning a partial view in this method, obviously that doesn't exist yet, so we'll need to make that now. Right click on your "ListMeta" method and select Add View. A dialog window will appear, make sure you fill it out just as I've done below.

76ed1ee5-5eba-4af3-8e87-8812e8afdbf4metaform_partial.png

Once your new partial view is created lets replace the code with the following:

    
@MetatagsExample.Models.MetaViewModel

< meta name="description" content="@Html.DisplayFor(modelItem => Model.Description)">
< meta name="keywords" content="@Html.DisplayFor(modelItem => Model.Description)">
< meta name="author" content="@Html.DisplayFor(modelItem => Model.Author)">

Lets open up our Details page for this controller by going to Views > Pages > Details.cshtml, we'll add the following lines to the top of our class (just below our @model code): 

 
    
@section metatags {
    @Html.Action("ListMeta", "Pages", new { id = Model.Id })
}

Now, lets open our _Layout.cshtml, which acts as a template for all of our future Pages and we'll add the following line inside our <head> tags:

    
@RenderSection("metatags", false)

Alright, we're ready to create our database!

Open your package manager console window by selecting view > other windows > package manager console. Once your console has opened we're going to run the following three commands individually.

  • enable-migrations
  • add-migration initial
  • update-database

If everything was successful, you now have a local database which will serve nicely for our example.

Build and Run

Finally, lets build and run our project. Once your project compiles and the browser opens. Navigate to the following URL:

localhost:{port}/pages/create

You'll see a create form, fill it out and click create. You've just created a "Page" that contains your specified meta data. After your record posts, you'll see a new screen with the results. Click the "details" link and you'll be taken to the details page.

Right-click and choose "View Source" and you should see your specified source as I've shown below

c59d96ea-e78a-4eef-8e25-f16ebd5228f2pagesource.png

That's it... If you have any problems just leave a comment and I'll try to clarify for you.