Howard Vining - Big Nerd Ranch Tue, 19 Oct 2021 17:46:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.5 An Introduction to Microsoft Azure Mobile Services https://bignerdranch.com/blog/an-introduction-to-microsoft-azure-mobile-services/ https://bignerdranch.com/blog/an-introduction-to-microsoft-azure-mobile-services/#respond Wed, 13 Aug 2014 12:01:06 +0000 https://nerdranchighq.wpengine.com/blog/an-introduction-to-microsoft-azure-mobile-services/ Microsoft Azure, a cloud storage and computing platform, is a one-stop shop for virtual machine hosting, web hosting, machine learning analysis, web-enabled databases, content delivery and more. Here's how to get started.

The post An Introduction to Microsoft Azure Mobile Services appeared first on Big Nerd Ranch.

]]>

Microsoft Azure, a cloud storage and computing platform, is a one-stop shop for virtual machine hosting, web hosting, machine learning analysis, web-enabled databases, content delivery and more.

Azure offers specialized services like API Management, which can act as a proxy that limits how often a developer can hit his or her APIs within a given time frame. You can push notifications to various mobile platforms using Notification Hubs. And if you are looking for a lightweight data store, then the Azure Redis Cache may be of interest. To that extent, Azure Mobile Services is a piece of the larger puzzle that enables devices of various platforms to take advantage of a core cloud-powered service. It is a RESTful data service that can be written in JavaScript (Node.js) or C#/VB.NET. As a data service, it’s backed by SQL Azure as the default, but there are options for MongoDB and Azure Table.

In this entry, I will introduce features of Azure Mobile Services from the JavaScript perspective. You can access Azure here, which requires a Windows Live account. Once a new service is created, you will begin at the quick start page, which contains all the platforms Azure Mobile Service supports with client SDKs.

Get started with Microsoft Azure

To date, those platforms are:

  • Windows Store Apps
  • Windows Phone 8/8.1
  • iOS
  • Android
  • Xamarin
  • PhoneGap
  • HTML5/JavaScript

The SDKs are open source and live here. Now let’s take a look at some of the features of Azure Mobile Services.

Tables

Under the Data tab, we are able to create entities in the data store that will back this mobile service. As stated before, by default Azure Mobile Service uses Azure SQL Database for storage.

When creating the table, you have the option to apply permissions to the CRUD (create, read, update, delete) operations on that table. These options are:

  • Anybody with the Application Key: Allows anyone who makes a request to the service with an application key to perform the respective action.
  • Only Authenticated Users: An action is available only to clients with a user who has completed the authentication process for one of the identity providers.
  • Only Scripts and Admins: The highest restriction. Allows only other scripts or admin users to invoke the action.
  • Everyone: Least strict, as it implies. Any client can perform the action with this permission.

Upon creating a new table, four columns are created automatically; id, __createdDate, __modifiedDate and __version. The id column is a String data type (nvarchar(MAX)) that acts as the primary key of the record, and as such it is automatically indexed. This value is automatically assigned a GUID when new records are added to the table. __createdAt and __updatedAt are straightforward. __version is a read-only timestamp column that changes upon each modification of the record. It is used during conditional requests as the Etag header. This helps in determining if a record is modified, thus removing the chance of updating a record with old or stale data.

Scripts

One of the more powerful aspects of Azure Mobile Services is the use of table scripts, which act very similarly to table triggers. On any of the actions that permissions are applied, we can establish side effects that invoke validation, business logic, relationship management, auditing/logging, etc.

Each script takes in three arguments: request, user and item. The request is the structure that contains the headers and body content (using request.js). The user is a representation of the current logged-in user through an identity provider who sent the request. If no user is logged in, the level property holds a value of anonymous. Item is the object (JSON representation of the entry) that the action is applied to.

API

You are capable of creating arbitrary APIs without needing to interact with a table. You can create a “listener” for the following HTTP methods:

  • GET
  • POST
  • PUT
  • PATCH
  • DELETE

Each HTTP method can have a permission applied to it (same model as table actions). In an API, you have access to the request and response objects. In a sense, an API allows the same amount of functionality as the table scripts. You are also capable of passing in parameters to the API for GET methods. The parameters reside in the request.query object, while the other HTTP method parameters appear in the request.body object.

Scheduler

Similar to table scripts and APIs, Mobile Services provides scheduled tasks that can be invoked at an interval per minute, hour, day, month or only on demand. The Scheduler is great for nightly jobs, tasks, clean-up processes or data gathering.

Push Notifications

Besides data storage and access, Azure Mobiles Services also provides the ability to send Push Notifications to supported platforms: Windows Store Apps, Windows Phone, iOS and Android. With the following functions, your mobile service can send small messages globally or to individual devices.

  • “push.wns” (Windows 8)
  • “push.apns” (Apple)
  • “push.gcm” (Android)
  • “push.mpns” (Windows Phone)

Identity

I mentioned earlier that table script permissions can determine if an action can be invoked, depending upon whether an authenticated user invokes it. This is possible because Azure Mobile Services allows users to authenticate through identity providers like Facebook, Google, Windows Live or Windows Active Directory. Mobile Services tries to simplify this process by providing a one-stop area for maintaining your OAuth credentials. An example of this is the ability to add scopes to the App Settings in the Configure area:

Scopes and App Settings

The Tip of the Iceberg

As we have seen, you can create new tables and new columns that have a predefined set of trigger-like scripts. In addition, arbitrary APIs can be created to provide additional operation. But this only the tip of the Azure Mobile Services iceberg. There are other neat offerings available, like Git publishing, custom authentication, SignalR and Service Bus integration, along with support for third-party services like Twilio, Pusher and SendGrid. If you would like to learn more about how to get started with Azure Mobile Services, check out Azure Mobile Services’ Getting Started Content and their Mobile blog posts.

The post An Introduction to Microsoft Azure Mobile Services appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/an-introduction-to-microsoft-azure-mobile-services/feed/ 0
Data-Driven iOS Development with ReactiveCocoa https://bignerdranch.com/blog/data-driven-ios-development-with-reactivecocoa/ https://bignerdranch.com/blog/data-driven-ios-development-with-reactivecocoa/#respond Mon, 03 Feb 2014 15:01:06 +0000 https://nerdranchighq.wpengine.com/blog/data-driven-ios-development-with-reactivecocoa/

Editor’s note: This post was co-authored by Howard Vining and Matt Mathias.

The post Data-Driven iOS Development with ReactiveCocoa appeared first on Big Nerd Ranch.

]]>

Editor’s note: This post was co-authored by Howard Vining and Matt Mathias.


ReactiveCocoa (RAC) is an Objective-C framework for Functional Reactive Programming that seeks to provide more concise, flow-based code. For some useful introductions to the framework, you might watch our Tech Talk; you could otherwise check out some introductory articles here, here, and here. Throughout this post, we’ll be assuming that you’re familiar with typical ReactiveCocoa nomenclature like streams, signals, subscribers, etc. These resources are great to get an initial flavor for RAC, but if you’re hungry for more like we were, then you’re likely to have difficulty finding a post that details a more fully-featured application with RAC. To that end, we created an application that makes heavy use of RAC. Our application demonstrates how to use RAC in your application’s network and user interface layers. Along the way, we’ll emphasize what we believe RAC does well, and will also highlight its limitations. We think one of RAC’s primary benefits is its ability to seamlessly bind your application’s models and UI to the flow of data that you wish to represent.

Getting Started with ReactiveCocoa

The first place to start is to bring RAC into your project. You have two options.

  1. You can incorporate RAC as a static library into your project using these directions.

  2. CocoaPods hosts some podspecs that have been supplied by some kind third parties.

For convenience, we used CocoaPods. We’d be remiss if we didn’t mention that CocoaDocs hosts a wonderful set of documentation for RAC. Be sure to check it out.

Reactive Stack Overflow

Our app utilizes Stack Overflow’s public API to list the website’s top questions for the following platforms: Android, iOS, Ruby and Windows Phone. We use a UITabBarController for view controller containment, and give it five tabs: one for each platform above, and a final tab for overall Top/Hot Questions. Each tab in the UITabBarController has a UINavigationController that will allow users to “drill down” into each question to expose its corresponding answers. Thus, while relatively simple, our app shows how RAC may be implemented to address several familiar programming challenges.

Using RACSignal

RSOTopQuestionsTableViewController is the “main” UITableViewController of our application; it serves as the primary screen for the user and displays the current top questions on Stack Overflow. The other domain-specific tabs work in much the same manner. Accordingly, this tableview controller an excellent starting point for showing what RAC offers in our project. Let’s begin with - (void)viewDidLoad and interrogate the following code:

    @weakify(self);
    RACSignal *topQuestionsSignal = [[sharedStore topQuestions] deliverOn:[RACScheduler mainThreadScheduler]];

We begin with the weakify macro to avoid creating strong reference cycles with self inside later blocks. Inside relevant blocks, we follow-up each weakify with strongify. Next, we create an instance of RACSignal to serve as our topQuestionsSignal. Recall that we use RACSignal to capture and deliver present and future values in the push-driven data stream of our concern. To create our signal, we send the message topQuestions to our sharedStore object, which is the single instance of our RSOStore class that is tasked with storing our top questions. Before we continue, let’s take a trip over to RSOStore.m to examine our topQuestions method.

    - (RACSignal *)topQuestions
    {
        RACSignal *signal = [[RSOWebServices sharedServices] fetchQuestionsWithTag:nil];
        return [self questionsForSignal:signal];
    }

As we can see, it sends a message to our web services singleton and returns a signal. Let’s go visit RSOWebServices to see what fetchQuestionsWithTag: does.

    - (RACSignal *)fetchQuestionsWithTag:(NSString *)tag
    {
        NSURL *fetchQuestionURL = [self createRelativeURLWithTag:tag];
        @weakify(self);
        RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    ...

This method also returns a RACSignal. We create the signal with the createSignal: class method on RACSignal. createSignal: takes a block with a parameter—in this case, the parameter is an id that conforms to the RACSubscriber protocol—and returns a RACDisposable object that encapsulates the work related to the teardown and clean up of subscriptions. It’s important to understand that the RACSubscriber protocol involves the tasks related to sending subscriber objects the data that result from the signal to which they subscribe.

    @strongify(self);
    NSURLSessionDataTask *task = [self.client dataTaskWithURL:fetchQuestionURL
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                if(error)
                {
                    [subscriber sendError:error];
                }
                else if(!data)
                {
                    NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"No data was received from the server."};
                    NSError *dataError = [NSError errorWithDomain:RSOErrorDomain code:RSOErrorCode userInfo:userInfo];
                    [subscriber sendError:dataError];
                }
                else
                {
                    NSError *jsonError;
                    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data
                                                                         options:NSJSONReadingMutableContainers
                                                                           error:&jsonError];
                    if(jsonError)
                    {
                        [subscriber sendError:jsonError];
                    }
                    else
                    {
                        [subscriber sendNext:dict[@"items"]];
                        [subscriber sendCompleted];
                    }
                }
            }];
            [task resume];
            return [RACDisposable disposableWithBlock:^{
            [task cancel];
            }];
        }];
        return signal;
    }

Inside createSignal:’s block, we create our URL and kick off an instance of NSURLSessionDataTask to get our top questions. Inside the completionHandler block for NSURLSessionDataTask, we sendError: to the subscriber if there is an error downloading the data. Otherwise, if there is data, we send sendNext:—with our data—and sendCompleted to our subscriber when we have finished downloading the questions. sendError:, sendNext:, and sendCompleted: are all required methods on the RACSubscriber protocol. Note that at the end of the createSignal: block, we make sure to return our RACDisposable to clean up after ourselves. In our case, we are ending the data task with [task cancel]. Finally, we return the signal resulting from our fetchQuestionsWithTag: method. With this signal in hand, we return to our topQuestions method in RSOStore.m. We call [self questionsForSignal:signal], careful to pass in our new signal, to fill out the data model for our top questions tableview. questionsForSignal: has the following implementation:

    - (RACSignal *)questionsForSignal:(RACSignal *)signal
    {
        return  [signal map:^(NSArray *questionDicts) {
            NSMutableArray *questions = [[NSMutableArray alloc]init];
            for(NSDictionary *questionDictionaryItem in questionsDicts)
            {
                RSOQuestion *question = [RSOQuestion questionForDictionary:questionDictionaryItem];
                [questions addObject:question];
            }
            return [questions copy];
        }];
    }

Just like the other methods we’ve discussed above, we are returning a RACSignal. Yet, we have a new concept introduced in this method’s implementation: map:. map: takes a block that is called on each unit of data in the signal. It returns a new RACSignal carrying the values returned by the block. In our case, our web service call is going to send down an array of JSON objects representing questions. Each item in the array is represented as a dictionary. We loop through these dictionaries, pull out question data from the dictionary item and place it in a mutable array. Take a look at the implementation of RSOQuestion if you’re interested in further details. At the end of this block, we return a copy of the array holding the questions for our table. At this point, we’re back in -viewDidLoad in RSOTopQuestionsTableViewController.m. Notice that we’re ensuring that the topQuestionsSignal is delivered on the main thread by passing in [RACScheduler mainThreadScheduler] to the argument for the method deliverOn:. We do so to avoid reloading our tableview from a background thread once we receive questions from our signal. Now that we have our signal, we have to use it.

    [topQuestionsSignal subscribeNext:^(NSArray *questions) {
       @strongify(self);
       [self loadQuestions:questions];
       } error:^(NSError *error) {
             [self displayError:[error localizedDescription] title:@"An error occurred"];
             [progressOverlay hide:YES];
         } completed:^{
             [progressOverlay hide:YES afterDelay:1];
         }];

topQuestionsSignal is sent - subscribeNext:error:completed:. This method takes three block arguments that are each executed in specific scenarios, and returns a RACDisposable object to aid in the clean up of the signal. subscribeNext: executes its block each time the signal sends a new value down the pipeline. In this case, the value sent down the signal is the array of questions for the tableview. As such, we execute our method to reload the tableview. error: will execute its block in the scenario that our signal returns an error; for example, loss of internet connection. The completed: block gives us an opportunity to perform some work that will be executed upon completion of our signal. We take this opportunity to hide our progress HUD. Note that a subscription to a signal is removed for a subscriber when the subscriber receives an error: or completed: event.

Refreshing the Tableview

Next, we initialize a UIRefreshControl to handle downward swipes to refresh the table’s list of questions. Remember, our previous subscription on topQuestionsSignal concluded (either with new question data or with an error), but that doesn’t mean we can’t reuse it.

    UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
    [[refreshControl rac_signalForControlEvents:UIControlEventValueChanged] subscribeNext:^(UIRefreshControl *refreshControl) {
            @strongify(self);
            [topQuestionsSignal subscribeNext:^(NSArray *questions){
                [self loadQuestions:questions];
            } error:^(NSError *error) {
                [self displayError:error.localizedDescription title:@"An error occurred"];
                [refreshControl endRefreshing];
            } completed:^{
                [refreshControl endRefreshing];
            }];
        }];
    self.refreshControl = refreshControl;

RAC provides a number of useful categories that allow the developer to graft RAC functionality onto system components. In the code above, rac_signalForControlEvents: comes from the category RACSignalSupport.h on UIControl. It allows us to hook into changes to our UIRefreshControl, which will send the event UIControlEventValueChanged whenever it is activated. Thus, we pass this control event into the argument for rac_signalForControlEvents:. In order to start listening for new data, we need to send subscribeNext: to the signal resulting from rac_signalForControlEvents:. subscribeNext: takes a block as before, and we specify a UIRefreshControl as the block’s parameter. When the UIRefreshControl is activated, it is sent down on the signal to the subscriber. Here, we take this opportunity to renew our subscription to topQuestionsSignal, which makes this signal “hot” once again. Doing so kicks off another web service request to Stack Overflow to see if any new top questions are available. In this manner, we refresh the table by simply renewing a subscription to a pre-existing signal.

Filtering the Tableview

The last bit of functionality that we’d like to highlight is the search box at the top of our tableview. We use this search box to filter the table’s content with the query string entered by the user in this text field. The search box utilizes the category RACSignalSupport.h that RAC provides on UITextField. This category yields an instance method called - (RACSignal *)rac_textSignal that creates and returns a signal for the receiving UITextField. The following code characterizes our approach:

    RACSignal *searchBoxSignal = [[[self.searchBox rac_textSignal] throttle:kSearchQueryThrottle] skip:1];
    RAC(self,filteredTopQuestions) =
    [RACSignal combineLatest:@[searchBoxSignal, topQuestionsSignal]
                      reduce:^id(NSString *filterString, NSArray *questions) {
                              @strongify(self);
                              if ([filterString length] > 0)
                              {
                                  NSPredicate *predicate = [NSPredicate predicateWithFormat:@"text contains %@", filterString];
                                  self.filteredTopQuestions = [questions filteredArrayUsingPredicate:predicate];
                                  return self.filteredTopQuestions;
                              }
                              else
                              {
                                  return questions;
                              }
    }];

The signal returned by rac_textSignal starts “hot” with the current text, and so we choose to skip: the first value. Accordingly, new values entered into the text field are sent down the signal only after the user begins adding text. Since we don’t want to filter the table too quickly, we elect to throttle: the signal by kSearchQueryThrottle (which is a constant we set equal to 0.6 seconds). The argument for throttle: takes an NSTimeInterval and only sends nexts to the subscriber after the given time interval. Ensuring to skip the on-subscription event and throttling future events allows us to reload our table appropriately. RAC() is a macro that will create a one-way binding between the signal produced by comebineLatest:reduce:and the property filteredTopQuestions on self. combineLatest:reduce: is a class method on RACSignal that takes an array of signals to combine as the argument for combineLatest. The reduce block, in our case, will return an NSArray corresponding to the array of filteredTopQuestions and takes two parameters that correspond to the returns types carried by the data stream represented by the signals in the combineLatest argument above. Inside the reduce block, we check to see if the filterString’s length is greater that 0 to ensure that a filterString exists. If so, we filter our top questions array according to filterString. If not, we return the full top questions array generated by our previous subscription to our existing topQuestionsSignal. In sum, our use of combineLatest:reduce: has the effect of combining two signals into one with the purpose of filtering our top questions array based upon the specified criteria.

That’s a wrap

We’ve accomplished a lot: created some signals, passed them through methods and classes, done some work on them along the way, used the results to fill out our data model and transformed our UI. Overall, this tour of RSOTopQuestionsTableViewController.m demonstrates the general approach each view controller takes in representing its content. Go ahead and play with the app! The above demonstration highlights several very powerful features of RAC:

  1. combineLatest:reduce allows the developer to combine signals into one. Doing so means that specific properties, to take our example, can be set according to complex logic determined by a single scope.

  2. Additionally, combineLatest:reduce: allows the developer to combine signals with completely different logic. For example, you can throttle: one signal and skip: the first three values for another. This combination can make your code at once more concise and flexible.

  3. Furthermore, throttle: offers a succinct way of adding time delay to an action or set of actions. This is done without the conventional, manual management of timers and threads.

  4. Perhaps more importantly, new values in the data streams captured by signals will be sent down automatically as they appear. This feature is a consequence of the side-effects of the signals being triggered by their subscriptions.

  5. sendNext: adds more control, as it provides the flexibility to manually push data down signals. To that point, RACSubjectis a signal that allows for manual management and provides even more flexibility (and responsibility!). See here and here for some implementation details and other considerations.

Some Final Thoughts

One of RAC’s exciting prospects is to alleviate the burden of all of those laborious checks for application state. Mobile applications are especially data hungry, and RAC provides developers a set of tools that can make matching our models and UI to the data they will consume much more convenient. Its block-based structure is also a huge win. Such convenience comes with some cost and risk. First, the syntax of RAC is at least a small departure from the code you may be used to typing. Second, RAC requires some fluency in a variety of new concepts in order to understand how to use the framework to solve problems. Third, and perhaps most controversially, while RAC aims to introduce functional programming into Objective-C, it cannot be entirely successful. For example, RAC cannot bind a data collection to a UI element (e.g., a tableview). As such, you will still need to use the tableview’s datasource methods to populate the table with data. For better or worse, your application’s code will not be completely functional. Cocoa just isn’t built that way; however, it is worth mentioning that Objective-C’s block-based present and future are taking and will take us further along the functional path. It is up to the developer (and the team) to ensure that the project’s code is coherent, effective and efficient. All in all, we think that RAC provides a wonderful suite of tools that, when appropriately implemented, can make some elements of your code easier to read, more maintainable and even more pleasurable to write.

The post Data-Driven iOS Development with ReactiveCocoa appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/data-driven-ios-development-with-reactivecocoa/feed/ 0