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 – 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 – Questions to ask before choosing an API to work on

In the last post, I ended by saying that developer time is valuable and to be selective about which APIs to work with. This post is going to talk about how to choose an API.

Why are you using the API?

If you’re building something for educational purposes or for fun, then the last two questions matter less. The questions are more geared towards people who want to build something that will be a good business or a feature that you want the company to add to their app.

What would be fun to work on?

If I’m into restaurants, Yelp and Foursquare easily come to mind.

Does the API solve your problem?

API limit what functionality they provide, called endpoints. Let’s say that I want to look at photos for restaurants. Do the Yelp and Foursquare APIs give me photos? They both do.

If I was looking for check-in information, Foursquare would have the edge because they were built on the check-in functionality.

What are the rules around API usage?

In their documentation, API typically have rules around how they can be used.

Foursquare’s rules are pretty open and clear on exceptions. I’m not sure if I would be “recreat[ing] the functionality of Yelp’s own website or mobile apps,” with the photo idea, which they say not to do.

Both APIs require attribution.

Foursquare only allows 4 pictures or tips to be shown from any one business.

With Yelp’s API, no data can be stored, while Foursquare requires that you refresh the data.

How easy is it to use? How well is it documented?

Good documentation is super helpful when you’re first starting out. I like that Yelp shows an example of their business response. Clarity around rules is also a must because it reduces hesitation over ambiguity.

How does the company treat it’s developers?

Do they communicate changes early in advance? Who owns the app that you make?

Foursquare seems to remove functionality and gives a few months for developers to adjust.

What is the longevity of the platform?

Deprecation of API features does make you wonder what they will remove next. How long do you think you can continue to use the API? How long before something else comes along that’s more popular?

In my hypothetical example, I have seen that Yelp has better search results though. In the end, I would choose Foursquare because it seems like you are free to do more with it.

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.

Flatiron School Week 5 Mistakes and Lessons

Topics: Autolayout, views, gesture recognizers

Symptom: The gesture recognizer doesn’t work.

Mistake: Making one recognizer and assigning it to four objects.

Each gesture recognizer can only have one owner and each assignment meant that it was just being reassigned to the latest view.

Lesson: Make one gesture recognizer for each object.


Symptom: Constraints were not working.

Mistake: I had assigned constraints to the view.

Lesson: Constraints are sent to the superview. Gesture recognizers are sent to the view.


Symptom: My game’s win conditions were being satisfied when they shouldn’t have been.

Mistake: When comparing the two views’ centers, I checked if the difference was less than a threshold, when I meant to use the absolute value of the difference.

Lesson: Unexpected wins are bugs too. They should be understood as much as bad bugs.


Symptom: My autolayout had more constraints than I thought I had specified.

Mistake: To deal with the iPhone size plus, I had constraints for when trait collections display scale were 3, but had forgotten to wrap the other constraints in an else statement.

Lesson: Those willTransitionToTraitCollection:withTraitCollection: methods can get really complicated and I have to be careful with the large if statements.


Flatiron School Week 4- Hacking together the TinderClone Swipe Feature

The Tinder Swipe

The central part of Tinder’s design is the swiping mechanism. The feature allows people to focus on one match at a time and make a decision before moving on to the next match.  Good for spending more time on matches and good for reducing the speed of data consumption.

I wanted to learn about animations, so this weekend I hacked together a prototype of the feature.

Demo

All the code can be found here along with a video demo. The code is very dirty, but that’s topic for another week.

Process

Step 1. Look up how to do it.

The next step in my TinderClone project is to make the swipeable images. Richard Kim has a really cool blog entry about how to make this feature three different ways. Since I’m taking on this project to learn to code, I took the “build it from scratch” way and tried to follow Nimrod Gutman’s blog. I totally failed. Twice.

It turns out that I didn’t really understand how UIView and UIImageViews worked. So, I decided to play around with them.

Step 2. Read up on UIViews

I read thought through the Apple View Programming Guide. in particular, the view and window architecture. I didn’t really understand bounds very well, so I started an Xcode project called playingWithBounds, that ended up being my project.

Take-aways:

  • Views are made on top of Core Animation layers (CALayer). Views have animation, but go to CALayer to one layer deeper for more control.
  • Subviews are arranged in an array in the superview.
  • UIContentMode is useful for sizing images. I played around with this later.
  • I thought the bounds property might have something to do with Box Sizing in CSS, but it’s much simpler. The bounds change the frame of the box.

UIView properties

  • frame- used for making objects. CGRectMake()
  • bounds- changes the size of the view, but not the center.
  • center- very important for moving objects around.
  • transform- used to rotate, move and scale objects. It’s the finishing touch. The object is drawn and then transformed. When an object is rotated, it remembers what it’s heigh and width were when it wasn’t rotated.
  • alpha- 1 is opaque and 0 is fully transparent. Great for
  • backgroundColor- useful for seeing where the rectangle is.

Step 3. Playing around with the UIView properties

I made single view project where I drew boxes and changed the bounds, and so on to see what would happen.

Step 4. Playing around with CGAffineTranform

When I got to Coordinate System Transformations, I started playing around with rotating and moving boxes.

I made a slider to rotate an UIImageView.

//slider
        CGRect slideFrame = CGRectMake(100, 400, 200, 20);
        self.pictureRotationAngle = [[UISlider alloc] initWithFrame:slideFrame];
        [self.view addSubview:self.pictureRotationAngle];
        self.pictureRotationAngle.minimumValue = 0;
        self.pictureRotationAngle.maximumValue = 2*M_PI;
        self.pictureRotationAngle.value = M_PI/2.0;
 
        [self.pictureRotationAngle addTarget:self action:@selector(rotateImage) forControlEvents:UIControlEventValueChanged];
 
        self.picture.transform = CGAffineTransformMakeRotation(self.pictureRotationAngle.value);

Step 5. Finding the Event Handling methods

Where other solutions mentioned at the top used UIGestureRecognizers, I imagined that these event handling methods could move my picture around too. They used UITouch objects.

I was touching my UIImageView and nothing was happening. Googling around, I found that UIImageViews are not user interactive by default. So, I had to set it.

    self.picture.userInteractionEnabled = YES;

I also set the

What is UITouch?

I didn’t know, so I built the first three methods and NSLogged the touch and event objects. They were very descriptive.

2014-10-27 18:58:26.919 TinderSwipeFeature[65292:2410541] <UITouch: 0x7fdf015533a0> phase: Moved tap count: 1 window: <UIWindow: 0x7fdf01409040; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7fdf01403730>; layer = <UIWindowLayer: 0x7fdf01414c50>> view: <UIImageView: 0x7fdf01684780; frame = (37.8671 64.9702; 402.124 402.124); transform = [0.99420459268393058, -0.10750454821160646, 0.10750454821160646, 0.99420459268393058, 0, 0]; clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x7fdf01684ac0>> location in window: {256, 332} previous location in window: {255, 332} location in view: {192.38019379786252, 249.92073845470227} previous location in view: {191.38598920517859, 249.81323390649064}

UITouch has a lot of really useful info:

  • Size of the screen: 375 width and 667 points height.
    frame = (0 0; 375 667)
  • The view touched and it’s location
    view: <UIImageView: 0x7fdf01684780; frame = (37.8671 64.9702; 402.124 402.124)
  • Current touch location in view and window
    location in window: {256, 332} 
    location in view: {192.38019379786252, 249.92073845470227}
  • Previous touch location in view and window
    previous location in window: {255, 332}
    previous location in view: {191.38598920517859, 249.81323390649064}
  • Timestamp
    2014-10-27 18:58:26.919

I now had the velocity of touches and I just needed to update the view being touched with a new center value to move it.

That was the key to solving the problem.

I added the other Tinder style animations associated with swiping. All of these were based on using the x location of the touch divided by the width of the phone to calculate a factor that would modify the rotation of the image and the opacity of the overlaps.

Step 6. Playing with contentMode

When I put the picture in the UIImageView, it would not fit in the frame, so I had to set clipsToBounds to YES and change the contentMode from UIViewContentModeScaleToFill to UIViewContentModeScaleAspectFill. UIViewContentModeScaleAspectFit also works but you get white space on the sides.

    self.picture.contentMode = UIViewContentModeScaleAspectFill;
    self.picture.clipsToBounds = YES;

The other options such as UIViewContentModeTop maintain the size of the image, and align the listed edge to the corresponding edge in the box. For example,

  • UIViewContentModeTop aligns the image to the top of the UIImageView.
  • UIViewContentModeTopLeft aligns the image to the top and left of the UIImageView.

Step 7. Animation timing

For the touchesEnded method, I wanted to animate the image moving back into location.

[UIView animateWithDuration:0.4 delay:0 usingSpringWithDamping:0.6 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
                ... reset image
            } completion:nil];

CGAffineTransformIdentity removes all transforms (rotations, scaling, translations).

Step 8. Animation for the picture flying off the screen or springing back

To animate the picture flying off to the side, I set a swipe threshold of 30% of the width.

if (differenceInTouchLocationX > aTouch.window.frame.size.width*0.2) {
            [UIView animateWithDuration:0.5 animations:^{
                viewTouched.center = CGPointMake(self.view.frame.size.width*2, currentLocation.y + 0.5 * speedY) ;
 
            }];
            NSLog(@"%@", aTouch);
        }else if (differenceInTouchLocationX < -aTouch.window.frame.size.width*0.3)
        {
            [UIView animateWithDuration:0.5 animations:^{
                viewTouched.center = CGPointMake(-self.view.frame.size.width*2, currentLocation.y + 0.5 * speedY) ;
            }];
        }
        else { 
             ... //springs back to original location
        }

Step 9. Add the overlap images (Like and Nope)

self.like = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 100, 50)];
 [self.like setFont:[UIFont systemFontOfSize:100]];
 self.like.text = @"L I K E";
 self.like.adjustsFontSizeToFitWidth = YES;
 [self.like setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];
 [self.like setTextColor:[UIColor colorWithRed:47/255.0f green:156/255.0f blue:28/255.0f alpha:1]];
// self.like.backgroundColor = [UIColor blueColor];
 self.like.transform = CGAffineTransformMakeRotation(-20* M_PI/180);
 self.like.alpha = 0;

Boy, I learned a lot by just reading the documentation and Googling. That was fun!

Flatiron School Week 4- Notes to Self

Blogging is an intentional investment in time

One reason I blog is to review what I’d learned that week.

The other goal in this blog is to document my creative process. There are two styles of documenting process.

  1. Make the thing, write about it afterwards.
  2. Record nuggets of information and write the blog entry along the way.

Both have their benefits and drawbacks.

  • The first gets to the answer faster, but misses out the details of the process.
  • The second slows down the discovery process, but maintains an accurate record of events. Errs on the side of too much detail that people won’t care about.

This weekend, I spent more time coding the Tinder swipe feature and didn’t have as much time to blog. I wanted to finish. I found that trying to recreate my process of discovery after the fact was time consuming and demotivating. Perhaps that’s not a good strategy. If I haven’t been taking notes along the way, I should just provide a summary of key points.

That’s probably what people care about anyway.

Flatiron School Week 4- Questions and Answers

Topics: Cocoapods and Core Data

Question: Should I use [array mutablecopy] or [NSMutableArray arrayFromArray:array]  ?

Answer: Both are the same if the array is already made. Stylistically, prefer the latter.


Question: Is order maintained in Core Data?

Answer: No, if you want to maintain order, add an attribute like createdAt and use an NSSortDescriptor to order by created time.