aceontech-blog
aceontech-blog
ACEONTECH/blog
15 posts
Don't wanna be here? Send us removal request.
aceontech-blog · 10 years ago
Text
So I guess we should be using NSCAssert(..)!
NSAssert References self
NSAssert and its related macros reference self. If you NSAssert in a block that self retains, you will create a retain cycle. This only occurs when running in any build configuration that doesn’t block assertions.
#define NSAssert(condition, desc, ...) \ do { \ __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \ if (!(condition)) { \ [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \ object:self file:[NSString stringWithUTF8String:__FILE__] \ lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \ } \ __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \ } while(0)
You can use NSCAssert to get around this, but that technically isn’t supposed to be used in Objective-C methods.
I discovered this bug while reading Drew Crawford’s post on NSNotificationCenter.
4 notes · View notes
aceontech-blog · 10 years ago
Text
Fixing linker errors when running unit tests on device
Ever seen a linker error on perfectly valid code, only when run from a unit test on device?
Undefined symbols for architecture arm64:  ... ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
Notice that your tests will most likely run just fine in the simulator. This often happens when referencing code in unit tests that aren't (yet) in use in the main executable.
You can easily fix this by disabling the Dead Code Stripping option in the linker build settings:
Tumblr media
It’s recommended to only change the Debug setting, so release builds remain optimized.
0 notes
aceontech-blog · 10 years ago
Text
iOS 9: How to trust enterprise developer profiles
Starting with iOS 9, Apple will no longer provide a way to trust enterprise developer profiles when they are first used. The user will have to dig through the settings manually, since they will only be able to dismiss the message:
... has not been trusted on this iPhone. Until this developer has been trusted, their enterprise apps will not be available for use.
Go to Settings - General - Profile - tap on the profile - tap on the Trust button
Thanks to Steve Chen over at Stackoverflow for the animated GIF.
0 notes
aceontech-blog · 10 years ago
Text
How to run Visual Studio Code from your Mac’s terminal
The instructions on Microsoft's page contain a small error which causes the parsing of .bash_profile to fail.
Turns out it's simply missing a semicolon near the end:
code () { VSCODE_CWD="$PWD" open -n -b "com.microsoft.VSCode" --args $*; }
After you make the correction, go ahead and restart your terminal session. You can now address VS Code from the terminal:
$ code .
Thanks to baf at Stackoverflow.
0 notes
aceontech-blog · 10 years ago
Photo
Tumblr media
Configuring Firefox's search box to always open results in a new tab:
Type about:config into the URL bar
Filter the list down to browser.search.openintab
Set it to true
0 notes
aceontech-blog · 10 years ago
Text
Origin of the CMD Symbol
Susan Kare spoke at the Layers conference this past week in San Francisco. During her presentation she showed the origin of the CMD symbol she designed for the original Mac. I had no idea it was so storied.
Here’s the CMD symbol as it looks today:
Through a book of obscure iconography, Susan Kare found this symbol used on Swedish road signs to indicate a landmark:
The Swedish symbol itself was inspired by an ancient castle on the island of Borgolm:
How cool is that?
32 notes · View notes
aceontech-blog · 10 years ago
Photo
Tumblr media
Nope, it's not an Watch.
0 notes
aceontech-blog · 11 years ago
Text
Smoother UI with AsyncDisplayKit from Facebook
To many developers’ delight, Apple’s introduction of flat design with iOS 7 finally retired skeuomorphic user interface design. For third-party developers, this resulted in significantly less time fiddling with borders, rounded corners and drop shadows. And thank goodness for that! Spiffy animations are now often used to infuse apps with that extra bit of oomph. These embellishments come at additional development effort, however. And more often than not, you will need to descend into lower-level APIs to achieve pleasing results.
UIKit is the most front-facing and mature framework in the development stack. Because it was designed in an era where restricted system resources were the norm, tradeoffs were unavoidably made in its system architecture. The most poignant example in my opinion is concurrency. Don’t be fooled, UIKit remains a single-threaded API (i.e. only usable from the main queue). It’s a classic example of the 80/20 rule: it works fine 80% of the time, but rapidly turns into a suffocating stricture for the remaining 20% of the cases where concurrency is required to deliver a smooth user experience.
iOS’s main queue* draws and animates the UI at 60 frames per second, which leaves surprisingly little time left for anything else. The actual available CPU time is in the range of 10 milliseconds per frame. Take note: the OS guards this with a vengeance and will rapidly start dropping frames if you exceed this narrow time slot too egregiously.
Facebook to the rescue..?!
Facebook, of all companies, recently open-sourced its framework for asynchronous UI called “AsyncDisplayKit”. From my limited time investigating its APIs and related documentation, I’ve deduced that it allows for the decoupling of UIView (and/or CALayer) instances from the main queue by introducing a new abstraction: nodes.
Tumblr media
Nodes are fully thread-safe and can be instantiated, laid-out and sized in the background as well as in parallel. They are supposed to behave like “drop-in replacements” for UIView and CALayer and don’t necessarily require a complete re-write.
This is extremely exciting news for me personally, as I was just researching ways to achieve background rendering of views (in addition to pre-rendering them in advance).
One of the framework’s developers gave a great introductory talk at NSLondon this year. It’s about an hour long and can be found on YouTube:
youtube
I’m keeping my eye on this one.
Notes
[*] queue: a multi-threading abstraction
0 notes
aceontech-blog · 11 years ago
Text
Combining Swift’s Lazy Properties with the Builder Pattern
My introduction to Apple’s new Swift programming language has been somewhat of a bipolar experience. Initially delighted by modern language features such as type inference and optionals, I rapidly became disappointed with the rigidity of its generics system and its lack of real reflection APIs. As I found out quite painstakingly, these limitations currently render Swift useless for more advanced types of projects (e.g. an IoC container). Remember that Swift is still very much 1.0 and will continue to evolve toward parity with Objective-C in the months to come. I’m not sure whether it’s wise to go full-Swift for production-grade applications just yet.
On a more positive note: the introduction of Swift brings language-level support for lazy loading of instance properties! When combined with the GoF’s Builder Pattern (with closures), it makes for an exceptionally succinct syntax.
Let’s take a look..
.. and start with an example of the end result:
class ViewController : UIViewController, MKMapViewDelegate { /** Create lazy property to the map view, initializing it with the convenience init function described in the class extension above */ lazy var mapView:MKMapView = MKMapView { m in m.delegate = self m.showsUserLocation = true // Do some other lazy init-related operation.. } }
At runtime, the first call to the mapView property will initialize its value and invoke the closure. Gone are the days of manual nil-checking a property’s backing ivar, and adding additional initialization code in the conditional if-case.
To make this work, you merely define an initializer which takes an optional closure (the builder). The MapKit example above worked because I added a convenience initializer to MKMapView using a Swift Extension:
import UIKit import MapKit extension MKMapView { /** Closure passes itself in */ public typealias MKMapViewBuilderClosure = (MKMapView) -> Void /** Add convenience initializer with the builder as its optional parameter */ public convenience init(builder:MKMapViewBuilderClosure?) { self.init() if let closure = builder { closure(self) } } }
An extension clearly isn’t necessary when dealing with your own classes, but it provides an easy way of tacking the Builder Pattern onto existing Cocoa Touch classes.
The if-let structure is part of Swift’s Optional language-feature. It simply checks the parameter’s validity and conditionally executes the code block when valid (i.e. the closure isn’t nil).
Is this really necessary? No. You could make do with regular initializer parameters. However, the closure-syntax allows for vertical property assignments and it provides a place for additional initialization local to the property being initialized.
Recommended
Take a look at ochococo’s GitHub repository “Design-Patterns-In-Swift”. It lists the Gang of Four’s software design patterns along with their implementations in Swift.
It’s a nice piece of work, albeit still somewhat incomplete.
0 notes
aceontech-blog · 11 years ago
Text
How to set up in-memory unit testing for Core Data
So, you're using Core Data in your iOS app. But what about unit testing (you are testing, right)? Setting up Core Data in-memory is easy:
#import #define EXP_SHORTHAND #import #import SpecBegin(CoreDataInMemorySetupExample) __block NSManagedObjectContext *context; beforeAll(^{ // ObjectModel from any models in app bundle NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil]; // Coordinator with in-mem store type NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel]; expect([coordinator addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:nil]).notTo.beNil; // Context with private queue context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; // Choose your concurrency type, or leave it off entirely context.persistentStoreCoordinator = coordinator; // TODO: At this point you would pass the context var to your code... }); afterAll(^{ context = nil; }); it(@"some test here", ^AsyncBlock { // TODO: write some expectations here which use the in-mem context set up above }); SpecEnd
0 notes
aceontech-blog · 11 years ago
Text
How to configure Travis-CI for iOS projects
Travis-CI.org is hosted continuous integration for open-source projects. The service is tightly integrated with GitHub; it validates builds and runs tests as commits are pushed. Best of all, it's free (with a fair-use policy) for public repositories. Initially a Ruby-oriented service, support for more languages have been added steadily. This conveniently includes Objective-C and iOS.
While self-hosted solutions like Jenkins are kludgy at best - requiring worker machines, VMs and a bunch of tricky configuration - Travis-CI is totally hands-off. Configuration is done through a single file, which resides at the root of your GitHub repository, called .travis.yml.
After hooking up your account, it's surprisingly easy to configure Travis-CI to build your iOS projects & run any unit tests you may have. If you use CocoaPods to manage dependencies, fear not, Travis knows how to handle this too.
The following .travis.yml builds all dependencies, the iOS project itself and runs all tests in the iOS Simulator (from aceontech/ReactiveNSXMLParser):
language: objective-c before_install: - gem install cocoapods --no-rdoc --no-ri --no-document --quiet - cd ReactiveNSXMLParserLib # Path to the Xcode workspace. #If you're using a project, use xcode_project: ... xcode_workspace: ReactiveNSXMLParserLib.xcworkspace # Define the Xcode scheme to use. Make sure the scheme is # "Shared" (in Xcode, menu Product > Scheme > Manage Schemes). xcode_scheme: ReactiveNSXMLParserLib # Instruct Travis to run tests in the simulator instead of a real device xcode_sdk: iphonesimulator
Shell commands you want to run the before install process (phase before the actual build, used for setting up to the build config) go in the before_install block. Said commands need to be indented as per the YAML spec and prefixed by a dash. If your Xcode project doesn't reside in the root of the repository (like ReactiveNSXMLParserLib/), this is also where you would cd into the right directory.
0 notes
aceontech-blog · 11 years ago
Text
@weakify(self): A more elegant solution to weakSelf in Objective-C
The introduction of Blocks and Automatic Reference Counting in Objective-C opened the way to drastically more concise code in the iOS developer community. Apple, too, is transitioning its APIs to this new model. And while ARC solves the majority of memory issues by obsoleting manual reference counting, the use of blocks often introduces a new gotcha: issues with capturing variables. Blocks clearly need to increase variables' retain counts during execution. Most of the time, this is exactly what you want; it keeps variables around long enough. However convenient, this also comes with a caveat specifically pertaining to capturing self.
It may be unclear to new Objective-C developers that referencing self in a block actually creates a 'strong reference cycle to self' (Apple). Because of the mechanics of ARC, Objective-C will prevent self from properly being deallocated, thus keeping it around indefinitely. Entire object graphs (UIViewControllers etc.) linger in memory this way and create memory leaks which accumulate over time. Needless to say, you will want to avoid this scenario at all cost.
Enter weakSelf
The obvious solution to this problem is to define a weak reference to self before the block (let's call it weakSelf), and use that instead while calling into self from a block. For example:
// Create a weak reference to self __weak typeof(self)weakSelf = self; [self.context performBlock:^{ // Create a strong reference to self, based on the previous weak reference. // This prevents a direct strong reference so we don't get into a retain cycle to self. // Also, it prevents self from becoming nil half-way, but still properly decrements the retain count // at the end of the block. __strong typeof(weakSelf)strongSelf = weakSelf; // Do something else NSError *error; [strongSelf.context save:&error]; // Do something else }];
Simple enough, but tedious and ugly. It's also error-prone, because human-beings have the tendency of being forgetful. I know I am, all the time.
Adding insult to injury, it's also a regular PITA to type over and over again. I recently came across one of @mattt's GitHub repositories and was delighted to find the Xcode snippet for weakSelf, which I mapped to defwself. Quite the time-saver:
"Weak Self" #Xcode snippet by @mattt http://t.co/IU3XIOSYhZ (installation instructions: http://t.co/0PeSjXd92b)
— Alex Manarpies (@aceontech) December 12, 2013
Hello @weakify(self)
It's awfully verbose, but a necessity. So just do it and thank me later. There is, however, one more optimization we can adopt: the @weakify() and @strongify() macros provided by the libextobjc library. Check it out:
#import // Do stuff @weakify(self) [self.context performBlock:^{ // Analog to strongSelf in previous code snippet. @strongify(self) // You can just reference self as you normally would. Hurray. NSError *error; [self.context save:&error]; // Do something }];
I love this solution because:
It's easy to type
It's easy to read and pick out with syntax highlighting
It obviates the use of variables like weakSelf and strongSelf, because it effectively shadows self
Adding it to your project (CocoaPods)
You can add the entire libextobjc via CocoaPods to your project, or choose to add just the libextobjc/EXTScope module.
If you're already using ReactiveCocoa, the macros are already available to you, since ReactiveCocoa depends on libextobjc.
A note on the use of macros
Sometimes it's okay to use macros.
0 notes
aceontech-blog · 12 years ago
Text
Hover.com Review
Hover.com is a nifty little domain registrar I heard about on one of Leo Laporte’s podcasts. This company is actually run by Tucows Inc. – a rather well known Internet establishment, famous for its software download portal, and its recent foray into the mobile world with Ting.com.
Hover strives to simplify domain name and email address management without dumbing it down to the point that the user loses control. In addition, Hover goes to great lengths in providing its customers with first class telephone and online support.
If you’re prospecting, I can assure you these aren’t tall tales. I have moved all of my domains and e-mail over to Hover.com in recent weeks. They’re dependable and affordable at $15 per domain. Domain names are the web’s plumbing of sorts – casual internet users pay little attention to them, after all, what’s in a name? However, more advanced users realize the added-value of good domain names. Because their lifetime can span multiple years – or in some cases – decades, I recently decided to consolidate my domains and e-mail addresses and move them to a single, trustworthy registrar. This turned out to be Hover.com.
Dumping (on?) GoDaddy
Of late, most of my hosting and DNS were managed by Go Daddy, a dirt-cheap and [slightly] lackluster provider based out of Arizona, USA. Go Daddy also appears to be one of the main competitors Hover is trying to target: they provide meticulous guides for Go Daddy customers on topics like unlocking domains, getting authorization codes and the like. Hover is quite clearly touting ease-of-use as its main vector for winning over Go Daddy users. And rightfully so: Go Daddy’s website must be the world’s most convoluted and hairy management interface ever. It turned out to be the single most irritating thing about the whole experience – it’s just so damn hard to figure out!
To be fair, Go Daddy did serve its purpose. Their “buy a domain and throw in hosting and email for free”-approach enabled me to own a bunch of domains and email aliases for next to nothing. But, I got what I bargained for in the end – a lousy management interface and non-existent support. Times have changed, however, and Hover fills in the gaps nicely, albeit at a marginally higher cost.
The Good
Fast and easy signup. True to Hover’s credo, the signup process was a frictionless experience. They make a point out of not upselling their other products and services. You only get what you ask for, and in this case that’s a good thing. There’s a fine line between apropos upselling and a downright bombardment of useless offers.
Sadly, Go Daddy falls right into the latter category. Even though these schemes allow for the occasional lightning deal, the customer is burdened with diligently reading the fine print before clicking “Next”. More often than not, customers are left behind somewhat distraught, and uncertain of their purchase.
Easy management interface. As stated above, administration of domain names and e-mail addresses is multitudes more convenient than some of the competition (I won’t harp on Go Daddy any further).
Customer service. While I haven’t required Hover’s telephone support services so far, I can vouch for their online support portal. The turnaround for e-mail based inquiries is one business day or less. They also follow up your request with care if required.
Transfer pricing at just $10. Customers who move over their domain get a great deal: one year over the existing renewal date for just 10 USD. You can optionally let Hover take care of all the transfer hassle free of charge.
[update] Free WHOIS/domain privacy. As Michael Yurechko mentions in the comments, Hover also offers WHOIS privacy at no additional cost, a service other registrars often charge for. With WHOIS privacy, your contact information is hidden from the public WHOIS registry. Hover’s administrative contact information is displayed instead. This keeps spam and other unsolicited email at bay. Thanks for the note, Michael!
The Bad
Regular pricing is slightly more expensive at $15 per year, per domain. Not quite the bargain when competing registrars come in at a lower price point, e.g. Go Daddy charges $13 for the first year (and $15 for subsequent renewals).
Mailbox pricing at $20 per e-mail address, per year. One sore point with Hover is the rather steep e-mail pricing. Even if all you’re doing is forward to another address, the same pricing structure is upheld. Go Daddy throws in e-mail for mere pennies. Put into perspective, on the other hand, one might argue that $1.67/month/mailbox is hardly a heist. It just depends on how many of them you intend to own, I guess.
No hosting. This is by no means a criticism; I was just dismayed to realize their great service does not extend to web hosting. Hover directs its customers to a select group of specialized hosting companies like SquareSpace and MediaTemple instead.
0 notes
aceontech-blog · 12 years ago
Link
0 notes
aceontech-blog · 12 years ago
Link
Summarized:
Multi-process operations: delegation
Result-oriented operations: blocks
0 notes