Tuesday, December 17, 2024

 I have taken a long-ish break from 100 Days of SwiftUI to do a couple of related things.  I am trying to really nail done SwiftData so I am doing the SwiftData by Example Collection.  Also, using what I have learned, thus far, I have created an app from a long languishing idea that has been waiting for me to turn it into an app on the AppStore.  I completed the business logic two years ago, but needed the time and SwiftUI experience to make it happen in a way that would make me happy.  It is in Test Flight now.  Every part of creating the app just flowed.  I knew what I wanted to do.  I knew how to execute each part of the app or knew where to get the info.  For this app, I had reached critical mass in my progress and I needed to create it.  I'll get back to learning SwiftUI in a week.

One more thing I discovered while doing this new app was how to get the Section Header to stay on the screen when scrolling the contents of the section.  Much like the secret of how to get buttons to recognize button taps when they are in a list row, you just had to somehow know or find the secret.  It was not discoverable.

var body: some View {

        List {

            Section(header: SectionHeaderView(total: users.count)) {

                ForEach(users) { user in

                    ListRowView(user: user)

                }

                .onDelete() { indexes in

                    users.remove(atOffsets: indexes)

                }

            }

        }

        .listStyle(.plain)

    }

}

Again, it was changing the style of a UI View.  Here, in order for the Section Header to be "sticky" and stay in view which scrolling the list up, the style of the list had be .listStyle(.plain).


Why this is?  I believe it is because of a complicated interaction with the default .insetGrouped listStyle support of sidebars on iPads and Macs.  That's all I know.  You need to apply this one non-default listStyle and then it works.  Magic.

(UL10)


Sunday, December 8, 2024

I have submitted a few dozen radars/feedbacks over the years since Swift was first released. While some have gotten more traction than others, the one's that really find honest to gosh broken functionality get fixed. The bug I detailed here was reported on to Apple on 11 Nov in Feedback: FB15764538. On 3 Dec, I was notified by Apple that they believe it was fixed in Xcode 16.2 Beta 3 and they asked me to test it. I did and they did indeed fix the issue. Success. Effort justified.

import SwiftUI

struct ContentView: View {
  @State private var text = ""
  var body: some View {
    VStack {
      TextField("Enter Text Here", text: $text)
        .foregroundStyle(text.count > 3 ? .primary : Color.red)
      Text(text)
        .foregroundStyle(text.count > 3 ? .primary : Color.red)
    }
  }
}

This is the simple test case I sent Apple detailing the problem with TextField.

We developers don't work for Apple, but we are a critical part of the app development eco-system. The folks who produce the developer tools and the libraries are not perfect but they try really hard to get as close as they can to that goal. We, 3rd party developers and hobbiests, play an important role in helping close that gap even more. 

And just in case you think that you don't need to report bugs like these, that someone else will, don't bet on it. This Feedback was marked as: 

           Recent Similar Reports:None 

While a bunch of reports on the same bug from multiple developers can help draw more attention to the really hard to find or solve problems, even more powerful is a simple bit of sample code that clearly reproduces the problem - pure gold for the engineer trying to find the issue. Be clear, be concise, be polite. 

I feel great when a bug like this gets fixed. I helped someone elses app shine because it wasn't hobbled by this bug. I helped another developer not waste hours tracking this same bug down in order to find a work-around. I helped an Apple Developer Tools Engineer get a little closer to their goal and feel justifiable pride in producing a product just a little better than it was the day before.

Also, thank you to @MartinAtElitappar on the HackingWithSwift+ forums who helped validate my conclusion that this was a bug and who encouraged me to report it to Apple.

(LU9)

Sunday, December 1, 2024

Back to Work

I took some extra time after family departed before I got back into 100 Days of SwiftUI.  For those keeping track, I am on Day 54.  I took extra time with the challenge on Day 47, Habit Tracker, not because it was difficult, but because I really wanted to pull together the concepts and try a couple of new things.  

One of the new things was adding buttons views in a list row. Turns out there is a secret to making this work. You have to read the documentation or get a bit lucky on StackExchange.  I really don't know how people coded before the internet.  Oh yeah, I remember.  I RTFM.  Anyhow, the problem was that tapping on the button in the list row, just selected the row.  The button press was not detected.  Turns out for the button press to be recognized, the .buttonStyle must be anything other than .automatic, the default.  My thanks to Ramis who provided the answer.  It has 312 likes (at the moment) so I think a great many others have searched for this answer.

The other issue was crafting an input screen that also served as a detail view.  The former was reached by an add button, sliding up a sheet.  The latter via tapping on the list row of an existing habit that was a NavigationLink to a detail view.  The two cases were differentiated by passing in the selectedHabit.  In the case of adding a new habit, the selectedHabit was nil.  In hindsight they certainly could have been two different views, but I enjoyed working out how to do it with a single Swift view.


Anyhow, I'm currently getting an introduction to SwiftData on Day 54 and enjoying replacing CoreData with all its quirks.  I'm too new to SwiftData, but I'm sure I'll be cursing its particular quirks soon enough.

 (LU8)

Friday, November 22, 2024

About to Take a Break

It has been a grueling week and by grueling I mean a pleasantly full week.  I have maintained my goal of trying to fit three days of SwiftUI into each day.  I have tried not to compromise learning the material to keep that pace.  I have reviewed the material, multiple times for items that are new and strange to me.  I have done the challenges completely, always attempting them on my own, but greatly appreciating that videos by Paul Hudson exist for HWS+ members.  I have spent time adding my own flairs to the apps where they have captivated me.  I have also been working with my programming/study partner.  I am so glad that we are chatting regularly again and that he is just as enthralled by Paul's lessons, as I am.

With a productive few days behind me, I'll now be taking a break.  Family is in town for the upcoming Holiday and my time will be devoted to them.  For those of you who celebrate it, I wish you a very Happy Thanksgiving.

(LU7)

Tuesday, November 19, 2024

Connected Again

As of last night, it had been two weeks since I had heard from my programming/study partner.  That was the Monday right before the election.  Between his interview scheduled on Wednesday and the results of the election, I figured he might be struggling and needing to regroup, so I let him know I was here when he was ready to reach out and to take care of himself.  I finally checked on him again via text to ask for proof of life and again let him know I was here for him.  He called me right back and, as I suspected, he was really hurting after the election results.  We chatted for a while and then agreed to work together tonight.  

After I got totally sidetracked the previous weekend tracking down an Apple bug, I made relatively slow but steady progress through the following week and weekend.  I am currently on day 40 of 100 Days of SwiftUI.  While way behind my original schedule, I have made some solid progress.  I especially like my resulting Word Scramble game, project 6.  


I made a great many tweaks, along the way and really have just one more major bug to resolve.  I generate all possible words that are makable from the source word with length 3-8.  I then run that list through Apple's UITextChecker() to determine actual legitimate English words.  This can take a couple of seconds at the start of every new game.  I need to make sure that happens completely in the background so I don't block the main thread.  Also, for the record one more time, UITextChecker() sucks.  It is reasonably fast, but it is really really bad at doing its one purpose, determining if a word is an actual word.

Anyway, after Word Scramble, I had great fun with the animation module.  SwiftUI is pretty amazing at generating some truly attractive effects with very little code and Paul Hudson does a great job highlighting that strength.

(LU6)

Monday, November 11, 2024

Going Strong and Then I Hit a Bump

So I was actually ahead of my self-imposed schedule.  I was really happy with my results and wanted to fix a few things and add a feature or two.  Then I hit a snag on 100 Days of SwiftUI, Project 5.  I'll go briefly into it here, but follow the link below for the full explanation and hopefully some helpful insights from others.

In an effort to add more visual clues when entering words for Project 5, WordScramble, I tried to change the color of the text in the TextField if the word being typed changed from invalid to valid and vice-versa.  The TextField ignored all efforts to make any style change to the text.  I could make changes to the appearance of the TextField but not to the text using such modifiers as .foregroundStyle(), .fontWeight(), and others.

https://www.hackingwithswift.com/forums/100-days-of-swiftui/unusual-behavior-when-trying-to-change-the-style-of-the-text-in-a-swiftui-textfield/28414

From here, I'm going to add a workaround for the above problem in WordScramble, add a feature to decide whether to keep the word successfully entered or to clear it, remove all the debugging code, file a bug with Apple, and move on!

Still no word from my programming study partner.

(LU5)

Thursday, November 7, 2024

A Productive Few Days Despite Current Events

So, a great amount has happened over the past four day.  I studied a great many 100 Days of SwiftUI lessons and I'm back on track. I worked with my study partner on Sunday and Monday (more on that below).  I did a whole bunch of testing for a new app from Paul Hudson, which he will release soon. Thank you for the opportunity, Paul.  And experienced a disastrous election cycle (from my perspective).

On the SwiftUI front, I have completed everything through Day 25.  I made some great updates and UI fixes to my projects, especially GuessThatFlag.  I am now working on Day 26 and hoping to complete Day 28 before bedtime.

Here are some screenshots from GuessTheFlag:

My study partner has gone silent again.  I wanted to hear about his coding interview yesterday, but there are a great many things that could be impacting him (the election, the interview, family issues), so I'm leaving him alone until he is ready to reach out.

(LU4)

Sunday, November 3, 2024

Big Push

So I reached out to my accountability partner last night.  And they reached back.  Excellent.  It would be so much worse if I had just gotten silence. 

So, as I kind of thought, they were struggling with their situation of having been laid off from their job.  There are a lot of feelings of anger and probably self-doubt.  It is good to sort through all that before rushing into finding another job.  Remember, getting laid-off says much more about the company's situation than it does about you, your abilities, and your worth.

Anyway, my partner is ready to get to work, and begin learning SwiftUI starting today.  Unfortunately, he is much more focused on a coding exam he has coming up on Wednesday than working on the fundamentals of SwiftUI.  So, I convinced him to get started on SwiftUI and I would find him a tutorial to work on in a day or so to prepare him for the programming test he thinks is coming.  It is a start.  

For me, I continue to push forward, accelerating the pace from the past week, as it is a weekend with no external commitments.   Also, I'm hoping my partner will inspire me, which should also increase my pace.

 (LU3)

Friday, November 1, 2024

One Week Into Leveling Up

 So, my accountability partner and I started 100 Days of SwiftUI a week ago.  My goal was three "days" per day.  That has not been the case.  I am averaging two per day and actually a hair less than that.  I have just completed my seventh day, and I have completed 13 days of SwiftUI.  So, how is my accountability partner doing?  I don't know.  They have gone silent.  After I post this, I will check in with them again and see if I get a response.

(LU2)

Friday, October 25, 2024

Starting to Level Up Again

 Okay, we are making that climb up the mountain again.  Every few years, after falling behind on the latest advancements in all things Apple Developer, I make a concerted effort to fill in the gaps that have been created during that timeframe.  I am told the best way to hold myself accountable for sustained superior performance in this area is to find a "study" partner or to post about my journey on social media.  Given my partner has proven even less reliable than me, I am resorting to posting.  I will start here on Blogger, but may finally dust off my microblog account if it still exists or start posting to Mastodon (rather than just following).  I will definitely NOT be posting to X (nee twitter).  Wish me luck!

(LU1)

Friday, October 29, 2021

Solving Coding Interview Problems

One of the reasons I got into programming was that I loved solving problems. Brain teasers, crosswords, Encyclopedia Brown mysteries, sudoku, those weird word problems with all those statements where you have to figure out who lives in the blue house - bring them on!  Programming gave me that same rush as when I solved one of those puzzles. However, one thing I hear continuously from my peers is that they hate coding interviews.  This is surprising as I find them comparable to solving a puzzle.

I get that coding interviews are artificial, that they bear little resemblance to real programming, and that they can be stress inducing especially when they prevent you from coding in the IDE of your choice (forcing you to code on a whiteboard or in CodePad).  But they can also be fun (in a non-masochistic way).

First, make your peace that you are going to be happy regardless of the result of the interview.  Second, treat the coding problems presented like the puzzles and exercises you do for fun.  If you can remove the stresses and instead have fun, you are far more likely not to suffer brain-freeze and to be more successful.

Let's take a simple common coding problem.  How do you check if two strings are anagrams of each other?  Anagrams have all the same letters, just in a different order.  That reminds me, make sure you understand the problem before you start trying to solve it.  As far as I know, no interviewer subtracts points from you for asking for clarification.

So let's give this one a whirl, solving it using Swift:

extension String {

    func isAnagram(str: String) -> Bool {

        var str = str

        for char in self {

            let index = str.firstIndex(of: char)

            guard index != nil else { return false }

            str.remove(at: index!)

        }

        return str.isEmpty

    }

}

Nicely done. You even made it an extension of String and followed the naming convention for functions returning Bool. This is a straightforward implementation that solves the problem in a clear, understandable way. We have a copy of the comparison string and we just keep removing letters that we have in the source string.  If we wind up with an empty string, we matched each letter of the source string, regardless of the order.  However, this solution has a computational complexity of O(2N-squared) where N is the number of characters in the string.  Can we do better?  

Is there a way we could organize each string such that they could be compared directly?  Since the two strings may be anagrams, they would have the same number of occurrences of each letter, that sounds like a counted set.  A counted set, is a set of unique items (in this case letters) and the number of times they occur.  We can implement it with a Dictionary.  

func isAnagram(str: String) -> Bool {

        var dictSelf = [Character : Int]()

        var dictStr = [Character : Int]()

        for char in self {

            let sum = dictSelf[char, default: 0]

            dictSelf[char] = sum + 1

        }

        for char in str {

            let sum = dictStr[char, default: 0]

            dictStr[char] = sum + 1

        }

        return dictSelf == dictStr

    }

We just created a dictionary with the letter as the key and the number of occurrences as the value.  The computational complexity of this solution is O(3N).  Creating each dictionary is O(N) as is the comparison.

Swift doesn't't directly implement CountedSet in its standard library, but Objective-C/Foundation does.  Using NSCountedSet, the above solution becomes a single line:

func isAnagram(str: String) -> Bool {

        return NSCountedSet(array: Array(self)) == NSCountedSet(array: Array(str))

    }

One other common solution to this problem which is not quite as efficient ( O(N㏒(N)) ) as the above but uses the same reasoning of arranging the strings in such a way that they can be compared directly is:

func isAnagram(str: String) -> Bool {

        return self.sorted() == str.sorted()

    }

This solution has the tentative advantage that it is directly supported in Swift and will be more easily understood by Swift developers.

There are usually many right answers to any programming problem or interview question.  Look for a way to represent the data in a way that helps you more easily solve the problem.  Remember to relax, have fun, and you will do your best.  Thank you to Kevin Tarr for suggesting this problem.  You can find videos by Kevin here on a variety of programming problems.

Thursday, July 23, 2015

Swift Fun Facts

Fact 1: Assigning a variable to itself is a compiler error.  I believe this is legal in Swift, but the LLVM compiler (Xcode 6 and 7) doesn't allow it.
var i = 0
i = i     <--- compiler gives error: "Assigning variable to itself"

Now why you would want to do this is another question entirely.

Fact 2: Trying to use Swift's print() statement inside an extension or subclass of an NSView brings up the print panel.  Despite having different argument lists, Xcode and the LLVM compiler would only recognize the NSView method print.  Swift's print was totally masked.  To access Swift's print function, preface it with:
Swift.print()

Fact 3: In strongly typed situations, Swift allows you to use just the enum member name without having to also use the enum type name.  For example:
enum CompassPoint {
    case North, South, East, West
}
var pointing: CompassPoint
pointing = .East  

I didn't have to use "CompassPoint.East".  This is great for readability and for saving time.  Now if Xcode's autocomplete would just get with the program in these strongly typed situations, I wouldn't have to type the enum name just to get it to list the members.  Feel free to duplicate this Apple Bug Reporter radar (rdar://21976034)

Opinion 1: 
Favorite Swift 2 feature: Protocol extensions and constraints
Welcome to the age of Protocol Oriented Programming

Friday, October 17, 2014

First Impressions of OS X Yosemite

First Impressions of Yosemite

So I stayed up late last night to install Yosemite on both my computers.  First Yosemite impressions are of translucence EVERYWHERE and of supersaturated colors.  The colors pop even to the point of distraction because so many other aspects of the user interface have been de-emphasized. Buttons and other controls have been simplified and flattened.  Chrome/window dressing has been almost eliminated so that your content is front and center.
I guess the reasons for these changes are to emphasize content, maximize use of space, and reduce distractions.  However I am not sure the goal has been realized.  The colors on the dock are so bright they overcome most of the benefit of reducing districts elsewhere.  I guess I will have to change the setting on my dock to be out of sight.  It never bothered me before but now it does.
Other highlights for me:

  • Mail seems to be working again.  Hallelujah!  I have struggled the last few years using Mail under Mountain Lion and Mavericks.  My gmail account would constantly stall and hang.  I would have to quit and restart mail multiple times a day to get it working again.  I kept the activity window always in view.  I would find mail on my phone that never showed up in my inbox on my Mac (I could find in my gmail archive folder).  After 24-hours all seems well.  
  • Phone calls on my Mac.  This is proving a little touchy.  I tried to place a phone call on my Mac - and it kept reporting that my Mac and iPhone had to be on the same local network.  After disconnecting and re-connecting my Mac and iPhone from my wi-fi network, it worked.  Receiving a call while using my Mac comes through FaceTime.  Fortunately, video is turned off by default unless specifically turned on.  Watch out for mis-clicks.  Also, when I got notified of an incoming call while using my Mac, I wanted to answer the call on my phone.  I closed my MacBook to answer the call on my iPhone and by doing so, I disconnected the call.  These are early days and I’m sure rough edges like these will show up and be addressed in updates.
  • iCloud Drive.  This can be a little anxious to set up initially, but worked perfectly.  The warning that your iCloud data will be inaccessible once you upgrade unless your other devices are upgraded to iOS 8 or Yosemite is scary but it lists your all devices and I knew what to expect.  The iCloud Drive was a little slow to access the first time - Finder just kept showing me a blank window or the files from the last selected folder when I tried to access iCloud Drive initially.  Things finally synced up and all was well.  Some indications of syncing would be helpful.  Comparisons to Dropbox® will be plentiful and this is at least one place where Dropbox does a better job.  iCloud Drive is a change of direction for Apple.  Initially, Apple seemed intent on doing away with the file system for cloud based files and mobile applications.  They have either retreated from this far-sighted strategy or have admitted defeat.  Being Apple, means never having to explain.

Every new OS X, John Siracusa does a detailed and magnificent review for Ars Technica.  The one for Yosemite can be found at: http://arstechnica.com/apple/2014/10/os-x-10-10/

The new site Six Colors features the writing of columnist Jason Snell.  I cannot recommend it strongly enough.  His review can be found at: http://sixcolors.com/post/2014/10/os-x-yosemite-review/

Thursday, October 16, 2014

New iPads

The new iPads look awesome.  I have been nursing an original iPad which has become less and less useful as iOS has advanced and the apps I use drop support for older models.  Looking at the comparisons that Phil Schiller showed of up to 12X greater CPU performance and 180X greater GPU performance, I got the feeling that it was time for a new iPad. I have squeezed all the value I could from my original purchase.  I am feeling very good about ordering my new iPad later today.  Now I just have to decide on a color: Silver, Gold, or Space Gray.

Sunday, September 14, 2014

A Fascinating Feature of Swift

I was just re-reading the swift book, The Swift Programming Language, and came across a feature that I overlooked the first time.

You can define a collection whose type is a protocol type.  This collection can include a bunch of objects of different types that all conform to a single protocol.  

Why is this useful?  When working with values whose type is a protocol type, methods and properties outside the protocol definition are not available.  This allows you to have a collection of different objects, but narrowly define the set of operations on that collection through the protocol type of the collection.  What a great way to create a particular perspective on a collection of different objects.

I can use the protocol to encapsulate the reasons I brought these different objects together, preventing unintended access to methods and properties outside the scope of why I brought these objects together.  This has great security benefits.  While we usually think of protocols as a way to extend objects, we can also use protocols to define a subset of existing capabilities of a set of objects.

Swift is a huge language and it continues to grow.  But even with the current features, there are further depths to explore.

Wednesday, September 3, 2014

Apple to Introduce Updated Hardware and New Product Categories on 9.9.14

At the moment, Xcode 6 Beta 7 has just been released.  We are less than a week from Apple's announcement of new hardware this Fall (Apple teaser: "Wish we could say more").  iOS 8 has been stuck at Beta 5 for a month.  My guess is that Apple may be ahead of the game on iOS 8 and are holding off releasing another beta because of support for unannounced hardware and features in the latest builds they don't wish to become public until the announcement on 9.9.14.

People are always trying to find hidden meanings from the teasers on the announcement invites.  I warrant this one is just a tongue-in-cheek reference to all the times Tim Cook avoided the "what's coming next" question.  Apple will be saying plenty come 9.9.14.

Thursday, August 21, 2014

Vulnerability


I am a bit of an Amanda Palmer fan.  She is a singer/songwriter who really puts herself out there.  She has the ability to make me laugh or cry, not every time, but with enough regularity that she must be tapping into something very raw and human. So, I pay some attention when she produces something.  I am on her mailing list and I get a notice from her (she writes infrequently) that she has a new book coming out.  Now I know this because I have read what she and others have written about how she twisted her life around in order to be able to write it.  So I get this notice which basically just tells me it how to get my hands on hew new book.  Now, honestly, I am not that interested in her book.  I saw her TED talk on the topic and I was wholly satisfied by that.  I am not interested in more details or the broader ramifications or how I too can put this into practice in my own life.  I got what I think I needed to know from her TED talk.  So I am looking at the cover to her book which is so Amanda Palmer (painted writing on naked skin - human parchment), and I notice the forward is written by Brene Brown.  Now, Amanda's husband is Neil Gaiman, a pretty famous writer, but she's got some other person doing the forward which makes me curious so I google her, as one does when you have no idea who a person is but maybe should. Up pops Brene Brown's TED talk.  So I am feeling a little guilty about my intention not to buy Amanda's book after she worked so hard on it and e-mailed me and all, so I decide I'll look at Brene's TED talk on vulnerability -  not my usual fair.  So, I watch the TED talk, find some non-obvious truths there to which I happen to ascribe and decide to share it with you.  You may already know all these truths but sometimes its nice to get a little affirmation about why we keep putting ourselves out there and getting our hearts roughed up a little.

Monday, June 30, 2014

New Jersey Summers

The only two things I like about New Jersey are blueberries in the Summer and being less than 90 minutes from Island Beach State Park.  The most fun a family can have for $5.

Wednesday, November 11, 2009

Introduction

This is the first post in my first blog. All blogs are an act of hubris. In the minds of the authors, they have something to say, to communicate to others, and so they publish in on-line diaries, public to all. I promise no great pearls of wisdom, no keen insights into the topic du jour being discussed. If you choose to read this blog, it is at your own risk of wasting time. What you'll see is what I need to express outside my head, but it will be 100% me.

We'll see where this goes.

VR/ Michael