How to preserve a button’s height and width in a UIStackView with distribution fill

Leave a comment

Not sure if there is a simpler way to do this, but if you have a button and you don’t want it to fill the entire StackView width and height, place it inside another view within the stackView and set leading/trailing/top/bottom constraints on it it.

Screen Shot 2017-07-09 at 7.34.40 PM.png

Kent Beck Tweets

Leave a comment

These are some of my favorite tweets by Kent Beck.

Screen Shot 2017-07-05 at 11.19.35 AM.png

 

StackView element heights respected

Leave a comment

If you are having your UI elements fill your StackView more than you’d like

Screen Shot 2017-06-29 at 3.50.31 PM.png

Change the alignment from fill to center

Screen Shot 2017-06-29 at 3.51.03 PM.png

Screen Shot 2017-06-29 at 3.48.33 PM.png

This application is modifying the autolayout engine from a background thread

Leave a comment

This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes.

If you ever see this error in your console, it’s because you are trying up update the UI from the main thread.

The fix is simple. Find where you are doing the update, and that code on a background thread.


dispatch_async(dispatch_get_main_queue(), ^{
[self updateSubViewsWithTrack:track];
});

https://stackoverflow.com/questions/28302019/getting-a-this-application-is-modifying-the-autolayout-engine-error

How to autolayout to highest vertical extent – topLayoutGuide

Leave a comment

Instead of doing this

    if(isPhone5 || isPad) {
        navigationBarHeightPortrait = 64;
    }

You should be doing this

[self.previewMainView.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor constant:0.0].active = YES;
}

This pins the view to the top of the maximum viewable area taking into account the navigation bar, the status bar, and anything else that would block your views content.

Links that help
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621367-toplayoutguide
https://useyourloaf.com/blog/pain-free-constraints-with-layout-anchors/

Blocks

Leave a comment

https://www.appcoda.com/objective-c-blocks-tutorial/

A block is a self-contained, autonomous code fragment.

They can be used instead of delegate methods, written just in one place and not spread to many files.

Blocks are objects, so they can be stored to NSArray or NSDictionary data structures, as well as to be returned from methods, even to be assigned to variables.

ReturnType (^blockName)(Parameters);
NSString *(^composeName)(NSString *, NSString *);

If you return a value, you need a return statement.

int (^howMany)(int, int) = ^(int a, int b){
    return a + b;
};

But if you return void no return statement if needed.

void (^justAMessage)(NSString *) = ^(NSString *message){
   NSLog(@"%@", message);
};

You can declare a block, and then define it later.

    // Declare a block variable.
    void (^xyz)(void);
    
    // Some other code...
    
    // Define the block.
    xyz = ^(void){
        NSLog(@"What's up, Doc?");
    };

You can also define it as a property.

@interface ViewController ()
@property (nonatomic, strong) NSString *(^blockAsAMemberVar)(void);
@end

And then formally define it later.

_blockAsAMemberVar = ^(void){
        return @"This block is declared as a member variable!";
};

You call a block just like a C function

int (^howMany)(int, int) = ^(int a, int b){
        return a + b;
};

    
NSLog(@"%d", howmany(5, 10));

Here’s another

    NSDate *(^today)(void);
    
    today = ^(void){
        return [NSDate date];
    };
    
    NSLog(@"%@", today());

And if you ever need to change a variable within a block, use the double underscore

-(void)testBlockStorageType{
    __block int someValue = 10;
    
    int (^myOperation)(void) = ^(void){
        someValue += 5;
        
        return someValue + 10;
    };
    
    NSLog(@"%d", myOperation());
}

Blocks as Completion Handlers

A completion handler is the way for implementing callbacks using blocks.
A completion handler is nothing more than a block declaration passed as a parameter.

andCompletionHandler:(void(^)())completionHandler;
andCompletionHandler:(void (^)(int result))completionHandler;

This flips the functionality of the paremeters from being one of inputs, to being one of outputs returned by the block.

andCompletionHandler:(void(^)(<any block params>))completionHandler{
    ...
    ...
 
    // When the callback should happen:
    completionHandler(<any required parameters>);
}

By passing it as a parameter, we can call it from within out method passing in the paremeters we want to return to the original calling method. We flip it around. So instead of using the parameters passed in, we set them and return them on when we call the block.

There is nothing magically asynchronous about blocks by themselves. They are called synchronously just like any other code.

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self addNumber:5 withNumber:7 andCompletionHandler:^(int result) {
        NSLog(@"The result is %d", result);
    }];
}

-(void)addNumber:(int)number1 withNumber:(int)number2 andCompletionHandler:(void (^)(int result))completionHandler{
    int result = number1 + number2;
    completionHandler(result);
}

But what’s cool about blocks. You can do asynchronous things by throwing them onto different threads.

NSLog(@"Preparing to run code in secondary thread...");
    dispatch_queue_t myQueue = dispatch_queue_create("My Queue", NULL);
    dispatch_async(myQueue, ^{
        NSLog(@"Running code in secondary thread...");
        
        int value = 0;
        for (int i=0; i<100; i++) {
            for (int j=0; j<100; j++) {
                for (int n=0; n<100; n++) {
                    value += j;
                }
            }
        }
        
        NSLog(@"From secondary thread: value = %d", value);
    });
    
    NSLog(@"This is main thread again...");

How to create custom UITableViewHeader programmatically using autolayout

Leave a comment

Create a new UITableViewCell for the header. Add your autolayout contraints. Then use in ViewController.

TrackHeaderCell.h

#import <UIKit/UIKit.h>

@interface TrackHeaderCell : UITableViewCell
@property (strong, nonatomic) UILabel *titleLabel;
@end

TrackHeaderCell.m

#import "TrackHeaderCell.h"

@interface TrackHeaderCell()

@end

@implementation TrackHeaderCell

#pragma mark - Creation and Layout

- (instancetype) init
{
    self = [super init];
    if (!self) return self;

    [self setupTitleLabel];

    return self;
}

- (void) updateConstraints
{
    [self addViewConstraints];
    [super updateConstraints];
}

- (void)addViewConstraints
{
    NSLayoutConstraint *centerY = [NSLayoutConstraint constraintWithItem:self.titleLabel
                                                               attribute:NSLayoutAttributeCenterY
                                                               relatedBy:NSLayoutRelationEqual
                                                                  toItem:self.contentView
                                                               attribute:NSLayoutAttributeCenterY
                                                              multiplier:1
                                                                constant:0];

    NSLayoutConstraint *centerX = [NSLayoutConstraint constraintWithItem:self.titleLabel
                                                               attribute:NSLayoutAttributeCenterX
                                                               relatedBy:NSLayoutRelationEqual
                                                                  toItem:self.contentView
                                                               attribute:NSLayoutAttributeCenterX
                                                              multiplier:1
                                                                constant:0];

    NSArray<NSLayoutConstraint *> *constraints = @[centerX, centerY];

    [NSLayoutConstraint activateConstraints:constraints];
}

- (void)setupTitleLabel
{
    self.titleLabel = [UILabel new];
    self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;

    [self.contentView addSubview:self.titleLabel];
}

@end

ViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];

    TrackHeaderCell *tableHeaderView = [TrackHeaderCell new];
    tableHeaderView.titleLabel.text = @"Results";
    self.tableView.tableHeaderView = tableHeaderView;
}

Screen Shot 2017-06-14 at 6.11.21 AM.png

Older Entries

%d bloggers like this: