Friday, October 26, 2018

Feedback for my Apps.

I realized getting a hold of me directly through the App Store was difficult, so if you have an issue with any of my apps in the App Store, please post here in the comments and I will get back to you, thanks.

Saturday, October 21, 2017

iPhone Simulator Zombies, how to destroy them

If you're on the same machine for years, and multiple versions of OSX and Xcode, likely you'll build up a large list of simulators that show when you want to select a simulator to run your app on.

As of Xcode 9 this became a breaking feature (at least for me).  Xcode had a hard time scrolling through the massive list, so searching online found a few solutions, and I just compiled them together here:

1) Remove yourself from iOS teams you no longer work on.

As far as I can tell this is a recent addition, as before you had to ask the team admin to remove you.


2) Remove the profiles from your machine (might as well nuke them all).

The path to do this is here (credit goes to Alex from the Houston iPhone Developer UG):


3) Remove all the simulators you no longer need, I'd say remove all of them then reinstall the ones you want.

In Xcode go Window -> Devices and Simulators

Unfortunately there's no "Delete All" or select all feature.  You'll have to manually delete them 1 at a time.


Or if you're extremely brave (I'm not) you can try this in the command line:

Credit goes to Joao from the Houston iPhone Developers UG:


I totally do not know if this will work, you've been warned :)


4) Add back the simulators along with their versions of iOS you want.

In the same Devices and Simulators page in Xcode at the bottom there is an add button:


Now you should have a nice clean list of the simulators and the iOS versions to choose from:

(before it was about 10-20 simulators of the same type with just a certificate number next to it)






Monday, June 20, 2016

awakeFromNib, layoutSubviews, dequeueReusableCellWithIdentifier and what happens in what order

If you have customized code in your UITableViewCell subclass like myself, you usually have some

If you have customized code in your UITableViewCell subclass like myself, you usually have some startup code for the cell, usually setting some constraints, or colors of text, default placeholder, etc. It generally doesn't matter whether this code goes in awakeFromNib or layoutSubviews, as long as what you do after dequeueReusableCellWithIdentifier doesn't depend on logic in either of these startup methods.

In the case where it does, you need to know which one happens in which order, in my case I'm using a custom UITextView that has placeholder text, via a nice blog post on how to do that:

https://grokswift.com/uitextview-placeholder/

The issue was that when opening a form to fill out for a new document the text is empty, so you need placeholder text. On top of this I have a label that needs to show (alpha = 1) when text from the user is inputted. When no text exists in the TextView the label needs to animate away and the Placeholder text needs to appear.

So you can see the possible logic branches I have, the issue was that at first launch of the cell before any text is set (if text already exists), my custom placeholder UITextView needs to get setup with constraints, placeholder text, placeholder text color, etc. But when the text already exists it needs to be set after the deque method is called, which then should disable the label and put the real text in the TextView (thus disabling the placeholder).

I got in a bind because I couldn't figure out which of these 3 methods run in which order, in this case, print out to console obviously shows you.

Here's the 3 important parts of code:

(called from the UITableViewController)

let cell = tableView.dequeueReusableCellWithIdentifier(notesTextViewCellId)

(inside the UITableViewCell subclass)

override func layoutSubviews() {
    super.layoutSubviews()
    print("layoutSubviews called")

    // do startup code here?
}

override func awakeFromNib() {
    super.awakeFromNib()
    print("awakeFromNib called")

    // or here?
}

or both?

In my case it was both.

Constraints needed to be in the awakeFromNib() and setting the placeholder logic needed to be in the layoutSubviews() as that happens AFTER the cell is dequed, where the awakeFromNib() happens before.

Here's the order when printed out to the console:

awakeFromNib called
notesCell dequeued
layoutSubviews called

Tuesday, March 1, 2016

Draw a red border around your UIView for debugging purposes

A lot of the times, you're dealing with UITextViews and UITextFields that have the same

A lot of the times, you're dealing with UITextViews and UITextFields that have the same white background and border as the superviews they sit on top of. It's helpful every now and then to make sure they're obeying the constraints you want them to have. In my case, I made a self-contained UITextView that has a placeholder functionality but the textView wasn't constraining to the size of its container view.

DOH!

image

Ahh... needed better constraints:

func applyConstraintsToTextView() {

    if let validTextView = self.placeholderTextView {
        let viewsDictionary = ["textView":validTextView]
        self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[textView]|", options: [], metrics: nil, views: viewsDictionary))
        self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[textView]|", options: [], metrics: nil, views: viewsDictionary))
        setNeedsLayout()
    }
}

Now add this extension to UIView

extension UIView {

func drawRedBorder() {
    self.layer.borderColor = UIColor.redColor().CGColor
    self.layer.borderWidth = 1.0;
    }
}

simply call it on the view (any UIView subclass) and see where the borders are landing.

validTextView.drawRedBorder()

Much better...

image

Monday, February 15, 2016

Quickly add a simple UIActivityIndicator to your screen

Sometimes you need to quickly throw a progress indicator over your view while something processes

Sometimes you need to quickly throw a progress indicator over your view while something processes (hopefully in the background).

I've found this code to be useful for that situation. Apply to your needs.

UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithFrame:self.view.frame];
activityIndicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
activityIndicatorView.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5];
[self.view addSubview:activityIndicatorView];
[activityIndicatorView startAnimating];

[self.presentingViewController dismissViewControllerAnimated:YES completion:^{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
    dispatch_async(queue, ^{
        // do your processing in the background here
        dispatch_sync(dispatch_get_main_queue(), ^{
            // Update UI
            [activityIndicatorView stopAnimating];
            [activityIndicatorView removeFromSuperview];
        });
    });
}];

Sunday, January 17, 2016

Finder shortcut to open a directory path

I find myself using this a lot after a co-worker showed me. Basically, if you come across a directory path you need to get to, like to drop files into a folder or delete file, whatever, instead of manually clicking each directory to get to the destination, you can copy and paste the path into finder via

   ⌘ + Shift + G



Feedback for my Apps.

I realized getting a hold of me directly through the App Store was difficult, so if you have an issue with any of my apps in the App Store, ...