Archive

Uncategorized

Swift 3 is a reevaluation of the past 2 years and changes a lot from previous versions

Guidelines
SE-0023
https://github.com/apple/swift-evolution/blob/master/proposals/0023-api-guidelines.md

Principles
– Clarity is more important than brevity on the code

Strive for clear usage, omit needless Words

From:
Too vague
friends.removeItem(ted)
friends.removeObject(ted)
friends.removeElement(ted)

And
Too specific
friends.removePerson(ted)
views.removeViews(myView)

Too
Removing needless words, if a word is not contriuting to the clarity of a usage, remove it
friends.remove(ted)
views.remove(myView)

Getting towards to having clear code that is concise

What words are needed?
myView.addChild(view, atPoint:origin)

The specification of Child is important, as it gives the context of hierarchy for the parameter

myView.addChild(view, atPoint:origin)

Since the method already gives a strong type for the parameter, the method can only recieve CGPoint, so there is no need to respecify that we are passing a point via paramter. It doens’t give additional information.

myView.addChild(view, at:origin)

 

Claryfying the behaviour of the api
By adding
friends.remove(ted) remove(_:)
friends.remove(at: formerFriendPosition) remove(at:)

In swift a method is comprised by base name “remove” as well as the argument labels. Both methods are in the same method family and they specify via the paremeter label.

In Swift you can overload methods, only if it is essentially the same operation only overloaded with different types:
text.append(aCharacter) // append(_:)
text.append(aString)

Examples where to add a parameter label, as general rule, when it helps to read well gramatically:
truck.removeBoxes(withLabel: "A label")
viewController.dismiss(animated: true)
friends.insert(michael, at: friends.startIndex)

Mutating vs non-Mutating
The “ed/ing” rule
x.reverse() //mutating
let y = x.reversed() //nonmutating

documentDirectory.appendPathComponent(".list") // mutating
let documentFile = documentDirectory.appendingPathComponent(".list") //non mutating

New API/Two Names
One name that is appropiate for Objective-C and one for Swift

Objective-C “Stringly typed” method names
in Swift 2.2:
controller.addTarget(self, action: #selector(handleDrag(sender:for)))

New in Swift 3:
Setters:
self.perform(#selector(setter: Artist.name))

Keypaths (Pound keypaths)
instead of:
album.addObserver(self, forKeyPath:"artist.name")
now:
album.addObserver(self, forKeyPath:#keypath(Album.artist.name))
Compiler validates that are Objective-c properties produces the name to pass it down to the frameworks

For mixed projects (Obj-C + Swift) some namings might not be good for one or another language

Swift
extension MyController{

@objc(handleDrag:forEvent:)
func handleDrag(sender: UIController, for event: UIEvent){} //handleDrag(sender:for) doesn’t make to much sense for Objective-c, use annotation to specify the objective-c name
}

Generated Objective-C from above

@interface MyController()
- (void)handleDragWithSender:(UIControl *)sender for:(UIEvent *)event;
@end

Translate to Swifty APIs
Automatic translations with Swift compiler
1) inspects method names and use gramatic queues to infer first parameter labels
e.g:
func saveToURL(_ url:String)
func save(toURL url:NSURL)

2) inspects names to remove reduntant information
func save(toURL url:String, forSaveOperation saveOperation: UIDocumentSaveOperation)
func save(to url:NSURL, for saveOperation:UIDocumentSaveOperation)

3) Infer default values for common objective-c idioms, like completionHandlers or option sets
func save(to url:NSURL, for saveOperation:UIDocumentSaveOperation, comletionHandler: ((Bool) -> Void)? = nil)

4) New bridging value types like URL that bridge the Objective-C Objects
func save(to url:URL, for saveOperation:UIDocumentSaveOperation, comletionHandler: ((Bool) -> Void)? = nil)

Translate “stringly” typed API to swifty (ish) API
NS_EXTENSIBLE_STRING_ENUM to transform stringly typed objective to swift
e.g
NSString *NSCalendarIdentifierGregorian = "gregorian"
to
Objective-C
typedef NSString *NSCalendarIdentifier NS_EXTENSIBLE_STRING_ENUM
NSCalendarIdentifier NSCalendarIdentifierGregorian;

Generated Swift
Transformed to Strongly typed
struct NSCalendarIdentifier: RawRepresentable{
init(_ rawValue:String)
var rawValue: String{ get }
static let gregorian:NSCalendarIdentifier
}

use
let cal = NSCalendar(identifier: .gregorian)

with bridge
let cal = Calendar(identifier: .gregorian)

Translate C API into Swifty API
NS_SWIFT_NAME import globals as members of type

C
CFStringRef kCGColorWhite NS_SWIFT_NAME(CGColor.white)
Generated Swift
extension CGColor{ static let white:CFString }
Swift use
let color = CGColor.white

C
CGAffineTransform CGAffineTranformMakeTranslation(CGFloat tx, CGFloat ty) NS_SWIFT_NAME(CGAffineTransform.init(translationX:y:));
Generated Swift
extension CGAffineTransform{ init(translationX: CGFloat, y: CGFloat) }
use
let translat = CGAffineTransform(translationX: 1.0, y: 0.5)

Complete example:

From this:

Screen Shot 2016-06-15 at 17.17.42

 

To this:

Screen Shot 2016-06-15 at 17.17.29

 

Having problems with your migration of Parse Database to your own MongoDB?

Not very elegant but it works… You can export your data manually from Parse App > App Settings > General Export data. You’ll get the .zip export, run manually the mongodbimport command pointing to your database. But you need to adjust the json files, remove the “results” key and leave it as an array. Then execute this command in your terminal (do not connect to your db):

mongoimport -h [mongo-db] -d parse -c [class-name] -u [user] -p [password] --file [path-to-json-file] --jsonArray

Downside: User sessions can’t be exported, so user is unable to login, but works fine in early stage if you can let the user register again

First thing, the setup I am using to not get error:

timed out waiting 120 seconds for simulator to boot

Before Integration Script:
open -b com.apple.iphonesimulator

After Integration Script:
xcrun simctl shutdown booted
xcrun simctl erase all
killall "Simulator"

A bit of background:
The app I am developing has a sync process that begins right away as soon as the app is installed for the very first time (and subsequently each 24h). This first time the app runs, it stores in Keychain the credentials, so Login screen will never show up again in any future sync processes.

I am integrating now KIF integration tests and I want to run them on a Bot with XCode Server on an OSX Server.

I have built a test that does this sync process: waits for a notification, waits for login screen, enters credentials, clicks login, waits for notification when sync process is finished.

The first time this runs with the XCode Server bot, it works perfectly. But on the next ones, the app has already all the data and has already the credentials stored in Keychain, so this test would fail since none of the notification would be posted and the login screen would never appear.

Which means the simulator isn’t stateless, it has a state and a different one than the first time it is being launched.

To the point
Since I want to test this first sync process and don’t want to add if statements in my tests, I want to reset the Contents and Settings of the Simulator, before or after each continuous integration.

I have tried to trigger scripts before with:
xcrun simctl erase

But I was getting this error
Unable to erase contents and settings in current state: Booted

Then I added
xcrun simctl shutdown booted

But then the server wasn’t able to boot it. So I tried to boot it with the boot command but, it didn’t work. So I decided to try to clean after.

So now the after trigger script looked like this:

xcrun simctl shutdown booted
xcrun simctl erase all

Then I began to get the famous error
timed out waiting 120 seconds for simulator to boot

With all those tests and errors I was getting, the server always went into an inconsistent state, so I had to restart my machine to being able to test again.

Since the cleaning after wasn’t working, but still made sense to me. I ran the 2 line script, on my terminal on my machine with my user (not the server), and there the simulator went also into an inconsistent state. In the means of, it erased everything, but it didn’t look like it because it still was open and the app still seemed to be installed, until I restarted manually the simulator, then the app was gone.

So I thought, could be happening the same with the simulator on the server. This blog post http://joshuabrauer.com/2015/04/xcode-server-and-continuous-integration-ios gave me the hint to access with the server user.

Changed the password and just log in my computer as _xcsbuildd, with my new password. It might ask to add a new entry in the Keychain since I didn’t know the previous password.
There I saw the open simulator with the installed app.

————
By the way, it was quite some time before I realized that the simulator I was using for running my app, wasn’t the same as the one the server was using. My reasoning was, if the server is asking me what xcode it should use, why doesn’t it use the same simulator. Actually it seems that uses the same simulator, but different path for the device folders.
Anyway I got it when I saw the logs of the bot, the list of available devices inside a mysterious unaccessible _xcsbuildd folder.
————

I added
killall "Simulator"
To the after script.

This one seemed to be working, that way I wasn’t getting anymore error
timed out waiting 120 seconds for simulator to boot

But now I am getting error:

Assertion: Lost connection to test manager service

So I thought it might be because it can’t boot it, so I added a before trigger to force the boot.
open -b com.apple.iphonesimulator

So far it is being stable, but I am still testing. I am still getting sometimes the
Assertion: Lost connection to test manager service
error but, as I said, I am still finding it out. I might add a sleep after the booting of the simulator to give it time, hopefully that solves it.

Overall the feeling is that all this setup of Apple is not very stable, and finding out the issues is hard since it takes long and previous issues might be influencing good solutions.

Just google
timed out waiting 120 seconds for simulator to boot
and you’ll see so many entries of people getting this error and everybody trying different things.

Refactoring helps you develop code more quickly

Refactoring is something you do all the time in little bursts. You don’t decide to refactor, you refactor because you want to do something else, and refactoring helps you do that other thing.

The Rule of Three
The third time you do something similar, your refactor

Refactor when you add a function/feature
Whenever I have to think to understand what the code is doing, I ask myself if I can refactor the code to make that understanding more immediately apparent.

Thoughts
Overall:
A nice read to enforce your conviction to use Refactoring

Refactoring Design
In Chapter 2 Refactoring seems to be presented as a solution to thinking the upfront “best design”, kind of like if it was the perfect detergent for a stain.

What I think the use of Refactoring is kind of a natural evolution of a developer. As beginners we stress out on our first architecture /design, then you evolve a bit and consider that sometimes it is easier to just begin developing instead of sitting for weeks in front of blank paper, yes you might get stuck with the crappy first design on this project. But on the next step you will be almost Refactoring without doing a conscious exercise.
And then learn techniques to refactor

NodeJS
PDF-JS (Mozilla) https://github.com/mozilla/pdf.js/
Really good one, generates HTML problem in my case that the information is not structured and I need to be able to parse it and extract information
PDF2JSON https://github.com/modesty/pdf2json

PHP
http://www.pdfparser.org/
http://www.tcpdf.org/doc/code/classTCPDF__PARSER.html

PYTHON
http://www.unixuser.org/~euske/python/pdfminer/
Really good one, generates HTML problem in my case that the information is not structured and I need to be able to parse it and extract information

JAVA
http://stackoverflow.com/questions/3203790/parsing-pdf-files-especially-with-tables-with-pdfbox
http://www.idrsolutions.com/java-code-examples-for-pdf-files/
Tabular data
https://github.com/jazzido/tabula
http://opendata.stackexchange.com/questions/127/extracting-tables-from-multiple-pdfs
Ruby? https://github.com/jazzido/tabula-extractor

Recopilation
https://github.com/okfn/ideas/issues/52

Project Technologies Setup:

Screen Shot 2014-03-12 at 10.17.02

Parts:
JS: CoffeeScript – ChaplinJS – BackboneJS – jQuery – Lodash – RequireJS
HTML: Handlebars
CSS: SASS – Compass
 

FAQ:

Why the heck can’t I store the user in Chaplin.mediator.user?

Error:

"Uncaught TypeError: Can't add property user, object is not extensible"

Googling I get this: Object.preventExtensions() but couldn’t find any reference to this method in Chaplin’s code. But I do see a method called

seal

What’s this? –> Google: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal

Attempting to add new properties to a non-extensible object will fail

Well… ok but I would have thought that Chaplin has already the user property set. No, it isn’t set.

I was following the Chaplin project example of: https://github.com/chaplinjs/facebook-example

And there I found the piece of code, inside facebook_application.coffee

initMediator: ->
# Create a user property
Chaplin.mediator.user = null
# Seal the mediator
Chaplin.mediator.seal()

 
 
 
————————————————————————————————
Chaplin seems to be routing twice – Controllers actions seems to be called twice when clicked on links
Navigation setup:

<ul>
  <li><a class="header-link new" href="new">New</a></li>
  <li><a class="header-link approved" href="approved">Approved</a></li>
</ul>

 

No listener is attached to a to control it internally in the Chaplin.View

On a latest change a Chaplin.Layout had been attached:

      options.title ?= @title
      options.routeLinks = false
      @layout = new Layout options

Inside the controller:

    new: (params) -&gt;
      console.log 'ListController::new'
    approved: (params) -&gt;
      console.log 'ListController::approved'

This ended up logging twice when clicked on any link on the navigation

'ListController::new'
'ListController::new'

Googling “Chaplin internal links” -> http://docs.chaplinjs.org/chaplin.layout.html at first sight a big fat bold “routeLinks”

Set to false to deactivate internal routing. If false, chaplin won’t route links at all.

Changed Layout instantiation to:

      options.title ?= @title
      options.routeLinks = false
      @layout = new Layout options

I haven’t decided yet to use Chaplin’s internal routing or not, but at least nothing is called twice 🙂

http://thecodinglove.com/post/56797907621/when-i-learn-a-new-framework

————————————————————————————————
Chaplin.mediator.suscribe handlers are called twice in a controller

  Chaplin.mediator.subscribe 'logout', @onLogout
  Chaplin.mediator.subscribe 'login', @onLogin

Handler

  onLogin: ->
    console.log("AuthController::onLogin")

Each time I logged in and out I got a saw the console calling the log several times.

Screen Shot 2014-03-13 at 13.07.49

Something was not disposed or unsuscribed correctly.

Test 1:
Unsuscribe on dispose of the controller:

   dispose:()->
      Chaplin.mediator.unsubscribe 'logout'
      Chaplin.mediator.unsubscribe 'login'
      super

Which works… but I had other controllers running with similar event suscription but those where working correctly. Difference? Adding the context on the suscription call:

Looking like this

  Chaplin.mediator.subscribe 'logout', @onLogout, @
  Chaplin.mediator.subscribe 'login', @onLogin, @

Might be obvious for most… wasn’t for me ^^

Ok, so I have a pretty heavy app that does a sync process with a webservice to get a complete content of the app. It is going to be an Enterprise app, view products, order products, etc. The complete sync process (only the first one) takes around 30-40 minutes, lots of images, lots of data… I was getting Memory warnings at the end of the sync, of course it had to be at the end of the sync…. I have various sync services running, to do a propper analysis I isolated just one sync process.

Begin:

So I am having a nice heap growth of 1.08MB. Trying to find out what that is. I am doing a sync process over and over again with a json file of 41KB and downloading 130 images, 39 between 5-8KB and 97 from 60-400KBS

Begin status – Heap Growth of 1.08MB on each

 

Screen Shot 2013-08-24 at 10.43.25

Following the highest percentage on the Call Trees view, I see many things but the first one I find strange is the 4.6% for getting the path to the document directory.

Screen Shot 2013-08-24 at 10.41.43
This is the evil code:

- (NSString *)pathInDocumentDirectory:(NSString *)fileName
{
NSArray *documentDirectories =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);

NSString *baseDocPath = [documentDirectories objectAtIndex:0];

// Append passed in file name to that directory, return it
return [baseDocPath stringByAppendingPathComponent:fileName];
}

I am going to try out saving the baseDocPath to an instance variable to see how this affects. Tried out code:

- (NSString *)pathInDocumentDirectory:(NSString *)fileName
{
if (baseDocPath == nil) {
NSArray *documentDirectories =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);

baseDocPath = [documentDirectories objectAtIndex:0];

}
return [baseDocPath stringByAppendingPathComponent:fileName];
}

–> Heap went down almost 100KB (1.08MB to 909KB)
Screen Shot 2013-08-24 at 10.43.25

The call tree below makes me think that the NSManagedObjectContext fetch request stores a cache. But I do reset the NSManagedObjectContext each time I begin a new Sync, I have also tried to reset it each time I finish a sync. But this doesn’t make any difference.

–> No result

Right now I am leaving the app open to see if at some point the memory flushes. Even a simulation of a memory warning doesn’t decrease the memory usage.

Trying to refreshObject:mergeChanges:YES once the image of the correspondant Entity is not needed any more

–> No result

Trying to refreshObject:mergeChanges:NO

Source: stackoverflow

Apple docs

Finally, Core Data does not by default keep strong references to managed objects (unless they have unsaved changes). If you have lots of objects in memory, you should determine the owning references. Managed objects maintain strong references to each other through relationships, which can easily create strong reference cycles. You can break cycles by re-faulting objects (again by using the refreshObject:mergeChanges: method of NSManagedObjectContext).

–> No result

[self.context setStalenessInterval:0.0];
Source apple developer:

Sets the maximum length of time that may have elapsed since the store previously fetched data before fulfilling a fault issues a new fetch rather than using the previously-fetched data.
The maximum length of time that may have elapsed since the store previously fetched data before fulfilling a fault issues a new fetch rather than using the previously-fetched data.
A negative value represents an infinite value; 0.0 represents “no staleness acceptable”.

–> This increased a little bit the memory

Following guidelines:
Source apple developer

NSString *predicateString = [NSString stringWithFormat @"employeeID == $EMPLOYEE_ID"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString];

for (NSString *anID in employeeIDs) {
NSDictionary *variables = @{ @"EMPLOYEE_ID" : anID };
NSPredicate *localPredicate = [predicate predicateWithSubstitutionVariables:variables];

–> Won: 30KB
Screen Shot 2013-08-25 at 10.43.29

 

Replacing the stupid way to check the type of the incomming file:

previous:

//    NSMutableSet * matches = [NSMutableSet setWithSet:[CDAFileHelper videoFileTypeExtensions]];

//    NSPredicate *p = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",pathExtension];

//    [matches filterUsingPredicate:p];

–> Win: 175KB!!

 

Screen Shot 2013-08-25 at 11.00.25

 

Replaced calculating always the cache directory by storing it in a instance variable

return [[[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];

–> Win: 7-8KB

Screen Shot 2013-08-25 at 11.06.13

 

stupidly I was first serializing the json file to store it and then read it in again… removed the storing and just parsing the serialized json file:

–> Win: 72KB

Screen Shot 2013-08-25 at 11.40.36

 

Well… after many many hours…. an epifani… lesson learned

DO NOT ANALYZE HEAP GROWTH WITH ZOMBIES INSTRUMENTS!!!

It fucks everything up…

My new lovely heap growth after using Allocations instrument…

Screen Shot 2013-08-25 at 12.53.16

Apple tip on zombies instruments

Tip: The Zombies template causes memory growth because the zombies are never deallocated. So for iOS apps, use it with iOS Simulator rather than on the device itself. For the same reason, don’t use the Zombies template concurrently with the Leaks instrument.

Should this really be a “Tip” or a whole “Warning”!! I actually read it before… that is why I was using the simulator… but somehow I didn’t realize what the “causes memory growth” meant for my abandoned memory analysis

 

The memory issue was coming from somewhere else, acutally other Sync process. What helped me there, to not having memory warning issues, was to find the correct places, in specific batches, where to save the Core Data context.

– Avoid Capturing JSValues -> mantain a strong reference -> Prefer passing as arguments

– Avoid Captuing JSContexts -> mantain a strong reference to the Global object -> Use +[JSContext currentContext] inside of the blog

 

– JavaScriptCore uses garbage collection -> All references in JS are strong -> It doesn’t matter if you create reference cycles as the GC can handle them

– Memory management is mostly automatic -> JSValue keeps things alive for you as long as you use JSValue

– But attention to:

-> String JS values in Objective-C objects as instance variables -> Use JSManagedValue for that, it is a garbage collected reference.

JSManagedValue by itself  is a weak reference to a JavaScript value.

addMangedReference:withOwner turns JSManagedVAlue into a “garbage collected” reference -> if JS can find the owner it keeps the reference alive otherwise it is released

-> Adding JS fields to Objective-C objects, fields that are added in JS but are not present on the JSExport object

 

Threading:

JSVirtualMachin -> JSVM

– JSVM can contain multipe JSContexts

– you can have multiple JSVM with different multiple JSContexts

– JSValues can be passed between JSContext in the same JSVM

– but can not be passed between different JSVM -> each JSVM has its own heap and GC

– JavaScriptCore API is thread safe

– Locking granularity is at level of the VM, JS can be executed in different threads on the same VM but when one thread is executing JS no other thread can execute JS at the same time on the VM

– Use separate JSVM for concurrency

 

I was having troubles showing a simple MPMoviePlayerViewController… digging into stackoverflow everything pointed me to an issue of iOS 6 about rotations, and viewWillAppear/viewWillDisappear methods that are called from the root view controller.

What it actually was… was much more simpler than all this (now… after 2 hours of research..), this stackoverflow answer pointed me to the correct solution

http://stackoverflow.com/a/12950958

I was using

[[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:path]];

instead of:

[[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:path]];

This is how it should look like

NSString *path = [[NSBundle mainBundle] bundlePath];

path = [path stringByAppendingPathComponent:@"test.mp4"];

self.moviePlayerViewcontroller = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:path]];

 

Worst thing…  the error messages: NOTHING AT ALL