Flatiron School Presents – The Multipeer Connectivity Framework (Lattice)

Another Flatiron student and I were interested in the Multipeer Connectivity Framework in iOS, so we made a chat app called Lattice that uses multipeer in the event of a natural disaster as a demonstration of the technology.

I’m going to talk about how the basics of multipeer connectivity work.

The Multipeer Connectivity (MC) Framework

What does it do?

Multipeer allows devices to connect with others nearby without the internet.

How does it work?

Multipeer Connectivity is an implementation of mesh networking, creating a local network between devices within Wifi or Bluetooth range. Not only are new devices connected with devices within range but also with all devices that those devices are connected to, even if the destination device is not within range of the sender.

That’s the real power of mesh networks. If permitted, devices can send messages relayed through other devices.

How might this be useful?

  1. Mesh networks allow communication when internet infrastructure is damaged (such as natural disasters).
  2. Mesh networks allow communication when internet access is restricted by governments, seen in the protests of Hong Kong.
  3. Mesh networks allow communication in internet-less situation (camping trips, road trips, subway commutes, and foreign vacations).

Lattice – Demo Project

Before we dive into the nitty gritty, I’ve placed Lattice on Github, so you can see exactly how the snippets below are used.


Setting up the MCManager

We have a MCManager class, similar to an API manager or data store for Core Data. Four properties need to be set up.

MCPeerID

_peerID = [[MCPeerID alloc] initWithDisplayName:displayName];

This is the name of your device.

MCSession

_session = [[MCSession alloc] initWithPeer:self.peerID securityIdentity:nil encryptionPreference:MCEncryptionNone];
_session.delegate = self;

This is the session that your device will start. Think of a session like a chatroom.

MCNearbyServiceAdvertiser

_advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.peerID discoveryInfo:elements serviceType:LatticeServiceType];
self.advertiser.delegate = self;
[self.advertiser startAdvertisingPeer];

This adverser tells nearby browsers that it is looking to connect with a particular serviceType. DiscoveryInfo is a dictionary that the browser will receive when it finds this advertiser.

MCNearbyServiceBrowser

_browser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.peerID serviceType:LatticeServiceType];
self.browser.delegate = self;
[self.browser startBrowsingForPeers];

This browser looks for advertisers of a particular service type to connect to.


Connecting to Other Devices

Lattice, the demo app, will have an advertiser and browser running at the same time on each device.

Browser Finds Peer, Invites Peer

- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info
{
   [self.browser invitePeer:peerID toSession:self.session withContext:nil timeout:10]
}

When a browser finds an advertiser, it can parse the discoveryInfo that the advertiser set when it was created. In this case, we want the devices to connect automatically, so the browser sends an invitation to connect to the browser’s session.

Advertiser Accepts Invitation

- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOL, MCSession *))invitationHandler
{ 
    invitationHandler(YES, self.session); 
}

Since we want the advertiser to connect automatically, the advertiser will reply YES to the invitation.

Session Confirms Connection

- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state

We can indeed confirm that the two devices are connected with this delegate method from the session. The session will tells us that the peer is now in the connected state.


Sending and Receiving Messages

Sending From the View Controller

[self.multipeerManager.session sendData:messageData toPeers:self.multipeerManager.session.connectedPeers withMode:MCSessionSendDataUnreliable error:&error];

Messages are sent from the session to the peers in the session.

Receiving In the MCManager

- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID
{
    //Kicks off a notification to the View Controller 
}

Messages are received by the session on the other devices. In Lattice, we triggered a notification with each message received.

Catching the Notification In the View Controller

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(peerDidReceiveDataWithNotification:) name:@"MCDidReceiveDataNotification" object:nil];
- (void)peerDidReceiveDataWithNotification:(NSNotification *)notification
{
    NSData *messageData = notification.userInfo[@"data"];
    NSArray *messages = [NSKeyedUnarchiver unarchiveObjectWithData:messageData];
    [self.demoData.messages addObject:messages[0]];
}

The notification was handled by the view controller to display the new message.


Limitations

iOS only

Multipeer Connectivity is a iOS framework.

Range can be limited on Bluetooth

We found it to be about 60 – 100 feet.

Downloading the app requires the internet?!

There should be a way for the app to spread virally with no internet.

Limited usefulness in zombie apocalypse

This would be great for finding survivors nearby without having to go room by room through scary dark buildings. During night when the zombies are outside, the bluetooth signal may not be long enough to communicate between buildings.


Special Thanks

Peter Fennema for showing how to connect via multipeer automatically

Jesse Squires for the messaging user interface: JSQMessagesViewController

Flatiron School Week 9 – Conquering Fear of Complex CocoaPods

For my Flatiron School Presents project, a classmate and I worked on a chat app.

For the chat user interface, I wanted it to look like Apple’s Messages app. There was a perfect CocoaPod for this: JSQMessagesViewController. After reading the Getting Started section, I still had no clue how to bridge the gap between my existing app and this UI. It was overwhelming and I was very discouraged.

9 Steps to Overcoming Fear of Complex CocoaPods

Step 1: Recognizing the problem

I knew that I was avoiding it. I looked for another CocoaPod but they weren’t quite the same. I even thought of building my own chat UI. I realized that I needed to be able to use CocoaPods though, so there was no getting around it.

Step 2: Read Zen Pencils

In need of inspiration, I turned to the Zen Pencils. I have the book too, which makes for very motivating reading.

Step 3: Go to sleep

It was 9 already and so I figured it was better to get some sleep than try that night.

Step 4: Try a simpler CocoaPod.

I hadn’t used enough CocoaPods up to this point, so I tried a smaller one. I looked at HPL chat. It had a tenth as many classes as JSQ did and I went for it. It didn’t work, but got me started.

Step 5: Look at the demo

The challenge of open source software is that there’s not always good documentation. It doesn’t cost money, but it costs time to read and understand how to use the code.

Fortunately, I saw that JSQ had a demo and downloaded it. Playing around with the demo really helped me understand how the pieces related to each other.

Step 6: Start customizing the demo

I didn’t need images or videos so, I got rid of the accessory button on the toolbar. I had to get familiar with the documentation to find which parts I needed to change. Once I removed the button, I felt much more confident about adapting the demo.

Step 7: Move the demo to a new project and make it work

Now I tried to make the demo fit my purpose, removing as much as I could to reduce it to the elements I needed. Here was a sandbox that I could use to unit test the functionality before I put it into my app and get everything tangled up.

Step 8. Add to the app

With the chat working on it’s own, I had to hook it up to my project. By this point, I realized that I just needed to make a couple  subclasses of the classes that the CocoaPod needed and replace my existing messages class with those.

Step 9. Fear Conquered

After I was done, I read the CocoaPod’s Getting Started again and now it all makes sense. Going through implementing this pod has been a process of gradual building of exposure, comfort and confidence with CocoaPods. I’m really happy that I did this. Fear of technology really comes down to not understanding how it works.

Flatiron School Week 9 – Resolving my first real git merge conflict

This week we started our client projects. 19 people broke down into teams of 4 or 5. There were four clients and our team had four people. This was the first time that I really needed to deal with git merge conflicts and develop a workflow.

It wasn’t long before I had a conflict.

There were three files that I conflicts with:

  1. AppDelegate.m
  2. the .pbxproj file
  3. a xccheckout file

1. AppDelegate.m

I knew how to resolve the first one, but as I tried to do that, my file directory on the left side of Xcode disappeared. It was time to ask for help. Zach, one of our TAs, helped me put together a plan to resolve the conflicts.

I had to back out of the merge, so I used

git merge --abort

and then reset the head to the last commit because there some uncommit changes that I didn’t want anymore.

git reset --hard <commit id>

2. the .pbxproj file

Apparently that file directory is stored in the .pbxproj file. The way that we resolved this was by telling git to just join the two versions together in the .gitattributes file by adding:

*.pbxproj merge=union

Another way to resolve this is to choose one version of the pbxproj.

git checkout --ours <directory/file>

Replace “ours” with “theirs” to get the version being merged into the current branch.

I had to add in some files that were no longer referenced by the pbxproj file after the merge using this second method.

3. a xccheckout file

For the .xccheckout file, this was a file that should have been ignored. I added this to the .gitignore file.

*.xccheckout

The problem was that both versions that I was trying to merge still had this file in tracked files. I had to remove this file from both repos by running:

git rm --cached <directory/file>

Once the .xccheckout file was removed, I could merge the two repos.

Both the .gitignore and .gitattributes files should be set up at the beginning of a project.

Update

Since that week, we’ve had to resolve conflicts many times. Following Github’s workflow has been pretty useful. I’ve found that the best way to resolve conflicts is prevention. We designed our workflow so that each person worked on a different part of the app and that minimized conflicts.

Flatiron School Week 7 – Week in Review

Topics: APIs + Core Data, Authentication, Multithreading

Mistakes and Lessons

Symptom: API calls don’t tell you a lot when they don’t work. I wasn’t getting anything out of an internet request. Debugging API calls can feel like a text based adventure.

Mistake: Errors in strings are hard to debug. Apparently, when I had made the url, there was an extra “%”.

Lesson: Copy and paste urls that work from Postman, or use an encoder to convert strings to urls.

Symptom: When I changed the colors in my bocce game, the logic for choosing the next team to go broke.

Mistake: I had changed my colors away from the default colors (e.x. blueColor) to RGB values and had used == to compare the objects. The correct way to compare the objects is using an isEqual. Turns out that when you use [UIColor colorName] using == to compare is ok because they are at the same memory location.

Lesson: Use isEqual with objects and == with primitives.

Notes to Self

There are some times when I just have to slow down and plan out how something works. I was making a tableView that updated an API and a Core Data store. This very quickly got too complicated to keep in memory and I had to write down the interactions step by stem.

My partner and I decided to divide and conquer a lab. It became very hard for me to test along the way, because I was dependent on his piece to make mine work.

“If You Want To Go Fast, Go Alone. If You Want To Go Far, Go Together”

Flatiron School Week 7 – BocceGame built with UIDynamicAnimator

UIKit Dynamics

In my spare time, I wanted to look at animating physics collisions so I found UI Dynamics. It’s a part of UIKit that has some build-in functionality to animate physics based interactions. It’s generally not used for games, but rather for transitions and cool UI tricks.

A bocce game is a simple way to demonstrate this functionality. In bocce, there’s a target ball called the jack and two teams try to get their ball as close to the jack as possible. The team gets points for the number of balls that are closer to the jack than the nearest opponent ball.

Bocce Game Demo

Github Repo

How to use UIDynamicAnimator

You have an animator.

Animators can add behaviors.

Behaviors can add items that they affect.

My animator

    self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];

One behavior is the UIDynamicItemBehavior behavior that allows the ball to continue moving after released by the hand with the add

self.linearVelocity = [[UIDynamicItemBehavior alloc] init];
[self.linearVelocity addLinearVelocity:velocity forItem:gesture.view];
[self.animator addBehavior:self.linearVelocity];

Another behavior is the collision behavior that collides with either a wall or another item.

//initialize collision behavior
self.collision = [[UICollisionBehavior alloc] init];
[self.animator addBehavior:self.collision];

How to make this game

Dragging a ball

Set up a UIPanGestureRecognizer that calls the dragged: method.

    UIPanGestureRecognizer *draggable = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragged:)];
    [self.currentBlock addGestureRecognizer:draggable];

The dragged method has the form:

- (void) dragged:(UIPanGestureRecognizer *)gesture
{
switch (gesture.state) {
case UIGestureRecognizerStateBegan:
//save the starting location
break;

case UIGestureRecognizerStateChanged:
{
CGPoint translation = [gesture translationInView:self.view];
 
//calculate the new location with the starting location and the translation
//set the location to the new location
 
break;
}
 
case UIGestureRecognizerStateEnded:
{
 
//figure out the velocity when the ball is released and add it to the item with the UIDynamicItemBehavior
}
 
break;
}
 
default:
break;
}

}
}

Continue a ball moving after release

Right now, the ball would stop when I let go of it. To keep it going at the same speed, get the velocity in view from the gestureRecognizer and add it to the UIDynamicItemBehavior with addLinearVelocity: forItem:

//Inside the case UIGestureRecognizerStateEnded
CGPoint velocity = [gesture velocityInView:self.view];
[self.linearVelocity addLinearVelocity:velocity forItem:gesture.view];
[self.animator addBehavior:self.linearVelocity];
 
//necessary to make the motion smooth, otherwise it will be jumpy if you hold down the 
[self.animator updateItemUsingCurrentState:gesture.view];

Stopping the ball

The ball will keep going on for a long time, so I needed to stop it somehow.

Stop the ball by adding friction. In UIDynamicItemBehavior, friction is the resistive force between two objects. I wanted resistance to simulate air resistance. Angular resistance was needed to stop the balls from spinning too.

self.linearVelocity.resistance = 8;
self.linearVelocity.angularResistance = 8;

Only allow one animation to run at a time

I found that trying to flick a ball before another had finished moving was making a really jumpy animation, so checked if the animation is running with each gesture recognized and only let the new block move after the other was finished moving.

- (void) dragged:(UIPanGestureRecognizer *)gesture
{
    if (![self.animator isRunning]) {
        switch (gesture.state) {
...

Detecting when the ball was stopped

To find out when to make the next block, I needed to know when the ball had stopped moving. I used the

- (void)dynamicAnimatorDidPause:(UIDynamicAnimator *)animator

method. It’s a delegate method so I had to set the

    self.animator.delegate = self;

Making the target ball bounce off the walls

I didn’t want the target ball to go off the screen, so I set the screen boundaries as walls,

[self.collision setTranslatesReferenceBoundsIntoBoundary:YES];

made the ball bound off all objects including boundaries (referenceBounds being those of self.view because the animator has self.view as the reference view),

[self.collision setCollisionMode:UICollisionBehaviorModeEverything];

and added another invisible wall, so that the ball would not end up on the top edge of the screen.

[self.collision addBoundaryWithIdentifier:@"end" fromPoint:CGPointMake(0, self.view.frame.size.height*0.1) toPoint:CGPointMake(self.view.frame.size.width, self.view.frame.size.height*0.1)];

Take the target ball out of collision

I wanted to make the target ball immovable, so I just had to remove it as an item of the collision.

[self.collision removeItem:self.currentBlock];

I also wanted future object to be able to go off the screen, so I removed the “end” boundary and the window boundaries.

[self.collision removeBoundaryWithIdentifier:@"end"];
[self.collision setTranslatesReferenceBoundsIntoBoundary:NO];

Ignoring most the call to dynamicAnimatorDidPause after a ball is made

After a new object is added, dynamicAnimatorDidPause is called, so I had to add a BOOL property justMadeBlock to ignore those calls.

Stop the moving block when it goes offscreen

If a ball was flicked too hard, then it would go off the screen and I would have to wait for it to stop before the next ball would load. To shorten that time, I made another boundary outside the edge of the screen and overwrote a delegate method to make the ball stop moving and not able to collide with other blocks.

[self.collision addBoundaryWithIdentifier:@"outOfBounds" forPath:[UIBezierPath bezierPathWithRect:CGRectMake(-90, -90, self.view.frame.size.width+180, self.view.frame.size.height+180)]];

Delegate method for the UICollisionBehavor

self.collision.collisionDelegate = self;
- (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p
{
    if ([((NSString *)identifier) isEqualToString:@"outOfBounds"]) {
        //not allow it to move
        [self.linearVelocity removeItem:item];
        //not allow it to interact with future blocks
        [self.collision removeItem:item];
    }
}

Calculate the nearest ball and marking the nearest ones

Once a colored ball had been thrown, there is now a winning ball (closest to the target).

I took all the balls on screen.

    NSArray *blocksOnScreen = [self.collision items];

Got their locations

Sorted the array of balls by location

And found the balls of the same color that were closest to the target ball

With those “winning balls”, I added a CALayer to them to mark them as winning.

The next to go would be the team further away from the target.

At the end of the game, a UIAlertController asks if you want to play again.

Adding indicators for the number of balls remaining per team

I used CAShapeLayers and added them to the self.view.layer. They would update as balls were made.

Adding a flashing turnIndicator

The alpha controls the opacity of the text label, so setAlpha:1.0 means make it appear.

UIViewAnimationOptionAutoreverse makes it disappear again.
UIViewAnimationOptionRepeat makes the animation keep going until you stop it.
UIViewAnimationOptionAllowUserInteraction allows you to remove the animation later on.

[UIView animateWithDuration:1.5 delay:0 options:UIViewAnimationOptionAutoreverse| UIViewAnimationOptionRepeat | UIViewAnimationOptionAllowUserInteraction  animations:^{
        [self.turnIndicator setAlpha:1.0];
    } completion:nil];

Stopping animations

When I tried to reset the game, setting all the properties back to nil worked well, except for stopping the turnIndicator animation.

There I found that the animation is in the layer of the animated object.

[self.turnIndicator.layer removeAllAnimations];

Choosing a more attractive color scheme

Adobe’s color wheel was really cool. I like pastel colors, so this is what I chose.

Notes to Self

Writing code takes way longer than expected

I didn’t think that it would take very long to make this, (just slap some blocks on a screen right?) but building features takes time and focus. Really quickly, seeing jumpy animations makes you want to fix them and that’s the 20% that takes the most time. Writing blogs about code also takes hours…

User testing is super important to do throughout

I knew how the game was played, but it wasn’t obvious to people I showed it to. I really wouldn’t have known if I hadn’t had someone use the game.

Don’t let sidetracked on super advanced features when the basics are not done

The flip side of asking for feedback is that people start giving you really good suggestions, but I think you have to finish one phase before hacking away at the next thing.

Hacking is fun with something quick, but it’s no fun with a big project

This is the second project that I’ve hacked to together. It’s been fun, but I really would have liked to have classes for the data model. This game was made over three weekends and I was finding that when I wanted to add new features, I had to recall the mental model that I had for the project. Instead I should have had a game class that remembered the model for me.

Flatiron School Week 6 – iOS Halftime Report

The Economics of Flatiron School

While I was still employed in Virginia, I thought long and hard about the value of going to a developer bootcamp.

Before deciding to come to the Flatiron School, I had gotten back into programming after a hiatus in college. I had taken a couple high school CS classes and I felt confident that I could learn to code on my own. I knew it would take longer than if I came to a bootcamp. Maybe 6 months instead of 3 months. $12K was a lot of money to me and having grown up without a lot of money, this would be the most money that I had spent on anything, so understandable this was a big decision. (I just noticed that it’s now $15K. My logic still applies.)

Whenever you quit a good job, there’s a lot of uncertainty. What if I don’t find another job? What if I don’t like New York?

Pre-Flatiron Pro/Con List

Pros:

  • A community of people to learn with
  • Frequent feedback from instructors
  • A structured environment that kept me moving forward
  • Placement services afterwards
  • Alumni connections
  • A commitment device
  • Getting a job 3 months earlier
  • Connect with the NYC tech community

Cons:

  • Spend 4-6 months of living expenses
  • Move to a more expensive city.

After a week, I realized that the math was actually really easy. Even if I got a job that was 60K, which is on the low end, I would be gaining $15K for having a job for three months earlier. So that by itself would equal the tuition, and I would be getting the other benefits thrown in as well.

That’s a no brainer, I gave my notice the next day.

A review of the first half

The Curriculum

We do a lot of labs here. One thing that I didn’t realize is that there is a lot of setup involved. In cooking, there is the concept of mise en place, or putting in place, that needs to be done before you can fire up the stove. It’s mostly cutting vegetables and measuring out slices and it’s really boring. Fortunately, the labs often have a lot of the setup done for us, so that we can get coding right away. That’s work that I would have had to do myself if I was learning on my own.

For the first six weeks, I’ve worked 55, 62, 60, 51, 62 and 52 hours, been able to do the labs and work on stuff on the side. I would say that 55-60 hours is probably a minimum number to everything done and work on side projects. I don’t think I would have worked this much on my own. The 12K was a commitment device to work hard. Being surrounded by talented and motivated people doesn’t hurt.

A lot of the iOS curriculum is being built out and sometimes I feel like a beta tester. That’s how something work though. No one is going to hand you perfect code. The swift change will also mean more changes for the curriculum. iOS is new and fast moving.

The Instructors

Most of the time, you can get a lot of instructions from tutorials, stack overflow and documentation. That’s when you don’t need an instructor. But there are also times when you hit on a problem that’s really annoying and you have no idea what to do. Apple Mach-o linker error is my least favorite. The error codes never make any sense. I google around for a while and don’t have the answer. That’s when you need an instructor.

The Students

Having 17 other people work on the same labs helps in a couple ways.

1. If you’re stuck, someone has the answer.

2. You solidify your learning when you explain a concept to someone else.

3. You crowdsource better ways to do the same thing.

Otherwise, I’ve been really impressed by the other students who come here. They’re thoughtful, entrepreneurial, artistic, and fun to hang out with. And they’ve all quit their jobs to be here, just like me.

One major advantage of working in a team is that you realize how hard git is with when you work with another person, something I would have waited to learn if I had taught myself.

The School

When you go to a “school”, it’s easy to forget that the Flatiron School is a startup. From hearing what the team believes, I think they know the importance of maintaining the brand and investing in the education of young people. They seem focused on the long term and building the HBS of developer schools.

Lunch

The school is in downtown New York. There’s a lot of places for lunch here.

Myself

Coming in, I had doubts about how much I’d prepared. I don’t feel that anymore. Six weeks in, I’m pretty comfortable that I can figure it out if I don’t know something. I know how to read Apple documentation, google stack overflow and ask for help. In fact, I think this comes more naturally to me than most people and the more code, the better I get.

This week, we learned about APIs and this was really the first time when coding became real. I can now build programs that change the state of the physical world. That feeling is incredibly empowering.

Notes for the second half

1. Maintain health

2. Appreciate the people and the time that we have left

3. Make good art

4. Do a lot of work

There’s two more weeks of instruction left before client projects start. My Flatiron presents is in three weeks, so there’s a lot to be excited about.

Flatiron School Week 6 – An analogy for understanding blocks

Blocks can be a really confusing concept and they’re further obfuscated by the crazy syntax. So crazy there’s a website just for the syntax.

Here’s one way to think about blocks.

If you’ve ever worked in a corporate office before, you know about making decks (powerpoint presentations) as I did in my former life.

  1. When your team needs to build a deck, your manager probably tells you to help him with a couple slides for the story he’s going to tell. He’s the architect but he doesn’t make graphs. So he IM’s you to make them and to tell him when you’re done. (Message one sent.) While he’s waiting for you, he’s continuing to work on other parts of the slide, so that he’s ready when you come back with the data.
  2. Let’s say that you can only make these fancy looking graphs for him and you don’t know what he’s going to do with it. This time, the data he needs is outside your normal scope. So you call up your friend over in finance to get the right numbers and ask him to email it to you. (Message two sent.) While he’s digging those out for you, you figure out how you want to display the data on the chart.
  3. Your friend get the data and emails it back to you.
  4. You take the data and put it in the graphs and send it to your manager.
  5. Your manager takes your graphs and puts it in the slide.

Congratulations! You’ve just used blocks.

Here’s what it would look like in code.

You have the Manager, Analyst, and DataAnalyst classes.

What does the manager need to do?

To the outside, the manager knows how to make decks, but they don’t know how the decks are made.

Manager.h

#import <Foundation/Foundation.h>

@interface Manager : NSObject

- (void)makeDeck;

@end

Manager.m

//
//  Manager.m
//  blockAnalogy
//
//  Created by Xida Zheng on 11/8/14.
//  Copyright (c) 2014 xidazheng. All rights reserved.
//

#import "Manager.h"
#import "Analyst.h"

@interface Manager ()
@property (strong, nonatomic) Analyst *analyst;

@end


@implementation Manager


- (void)makeDeck
{
    //make the start of the deck
    
    [self getGraphsFromAnalyst:self.analyst withCustomStyling:^(NSArray *graphs) {
        //any custom styling required for this deck
    }];
    
    //make the rest of the deck
}


- (void)getGraphsFromAnalyst:(Analyst *)analyst withCustomStyling:(void (^)(NSArray *))customStyling
{
    [analyst makeGraphsWithSpecifications:[NSDictionary new] CompletionEmail:^(NSArray *graphs) {
        //standard graph handling (i.e. put the graphs on slides)
        customStyling(graphs);
    }];
    
    //make the rest of content on the slides with graphs
}

@end

In order to make the deck, the manager, needs their analyst to get graphs and passes those graphs through any custom styling instructions before the slide makes it into the deck.

(Step 1.) Calling [analyst makeGraphsWithCompletionEmail…] is like IM’ing the analyst to make the graphs. The manager provides the analyst with specifications for the graphs and instructions for when the analyst is done.

What does the analyst do with that information?

(Step 2.) He takes it and translates the conversation with his manager into an algorithm to make the slides and a data request for his friend.

(Step 4.) After he receives a response back, he turns the data into graphs based on his manager’s specifications and send the graphs back to his manager via email.

//
//  Analyst.m
//  blockAnalogy
//
//  Created by Xida Zheng on 11/8/14.
//  Copyright (c) 2014 xidazheng. All rights reserved.
//

#import "Analyst.h"
#import "DataAnalyst.h"

@interface Analyst ()
@property (strong, nonatomic) DataAnalyst *friend;
@end


@implementation Analyst

- (void) makeGraphsWithSpecifications:(NSDictionary *)specifications CompletionEmail:(void (^)(NSArray *))completionEmail
{
    //turn specifications into a way to make for the graphs
    //turn specifications into a data request to your friend
    [self.friend getDataWithSpecifications:[NSDictionary new] CompletionEmail:^(NSString *data)    {
        //apply specifications with data
        NSArray *graphs = @[data];
        
        completionEmail(graphs);
    }];
    
    //make other graphs with data you're familiar with
}

@end

What did the data analyst friend have to do?

(Step 3.) Just take in the specifications from the analyst and send back the data in an email.

//
//  DataAnalyst.m
//  blockAnalogy
//
//  Created by Xida Zheng on 11/8/14.
//  Copyright (c) 2014 xidazheng. All rights reserved.
//

#import "DataAnalyst.h"

@implementation DataAnalyst

- (void) getDataWithSpecifications:(NSDictionary *)specifications CompletionEmail:(void (^)(NSString *))completionEmail
{
    NSString *data = @"data";
    
    completionEmail(data);
}

@end

I hope that helps clarify blocks. Let me know what you thought.

Remember, even though blocks are just funny looking objects, they’re misunderstood, and they deserve some love too.

Flatiron School Week 6 – Week in Review

Topics: Blocks, APIs

I’ve been writing three miniblogs a week on Mistakes and Lessons, Questions and Answers and Notes to Self. As I’ve progressed, I feel composition of my attention shift as well.

  • Since I’ve been making less time consuming mistakes and asking for help earlier, I don’t really have anything in the Mistakes and Lessons category. Since I’m still learning a lot, I’m going to call it Cool Stuff I Learned This Week
  • In terms of Questions and Answers, most of the questions I have are focused in areas that will take the form of side project demos.
  • I’ll still have making lots of Notes to Self.

My blog reflects that with a change in format with a Week in Review entry each week instead of three smaller ones.

Cool stuff I learned this week

  • UI changes must be made on the main thread.
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
         //stuff goes here ex:
         [self.tableView reloadView];
    }];
  • I didn’t know the difference between an access token and an API Client id & API Secret.
    The access token is used to authenticate an individual user, so that you can access their personal data.
    The client id and secret are used to authenticate to the API that you’re a registered app so that they allow you to continue to send many request to their server. This does not provide user authentication by itself.

Notes to Self

I like generalizing problems to find patterns in solutions and that turns out to be a really useful skill for a programmer, so that I can write reusable code.

Programming is very cumulative. Everything is built on a previously made part.

Playing chess while I was kid really helps me to visualize objects moving in my mind and that helps me keep track of blocks moving between classes.

Flatiron School Week 5 Notes to Self

I love animations.

Animation are the closest thing to art in iOS development. It’s like directing a movie or moving a paintbrush.

I started playing RGB express this week and I just love their level set up animation where the puzzle falls down from the sky in delayed stages.

Up next to explore: Core Animation, Core Graphics, and UIKit Dynamics

Flatiron School Week 5 Questions and Answers

Question: Should I be using frame or constraints to draw views in iOS?

Answer: Constraints. Autolayout will be able to adjust to the four different screen sizes, so you don’t have to. It’s like the CSS of iOS.


Question: I know how to animate the background color of a UIView from black to red with animateWithDuration … What do I use when I want to make it go from black to blue to red?

Answer: I could use two animations with different durations, or key frame animations.


Question: One of the labs this week was making a game with four draggable images. After finishing the lab, I noticed that I could drag multiple images at a time and that they would collapse to one location at the end of the drag, because I had only accounted for one object. How can I make it so that the user can only drag one object at a time?

Answer: One solution I found online used one gesture recognizer in the superview and detected which object was pressed using hitTest:. However, this did not solve my problem. I could still take the two. This question is still open, but I can imagine a solution where I store the locations of a four objects in an array and update it as I change each object’s location.