Playgrounds - Better playgrounds that work both for Objective-C and Swift

Overview

Swift Playgrounds... but supporting both Objective-C and Swift code, plus some superb features.

Watch demo

More in-depth overview video

Version License Platform

Playgrounds are one of the niftiest features of Swift. They allow you to quickly test out bits of code and see results in real time without going through traditional edit-compile-run-debug cycle.

"But surely playgrounds aren't possible in Objective-C" you say? ... In fact they can be much better than Swift ones.

Objective-C Playgrounds

Features:

  • Faster than Swift playgrounds (a lot)
  • Extra controls for tweaking:
    • values
    • images
  • Auto-animated values
  • Synchronizing DSL's
  • Buttons
  • IDE agnostic, once you run it, you can modify the code even from vim.
  • Full iOS simulator and access to all iOS features, so you can prototype production ready code.
  • Nice DSL for rapid prototyping
  • CocoaPods support, so you can add it to existing projects to experiment
  • Open source, anyone can contribute to make them better!

and it’s just a start.

Technical details

First, let’s establish naming:

  • Timeline is a place where you have snapshots and controls.
  • Worksheet is a place where you can add views / controls and have interaction with them. You can use all the stuff you’d normally use with iOS like UIGestureRecognizers etc.
  • Tick counter - number of times the code changes have been loaded, multiply by the time it takes to compile + load your project and you see how much time you saved.

DSL’s - Beautiful and fast way to prototype.

Timeline snapshots

KZPShow(obj)

  • CALayer
  • UIView
  • UIBezierPath
  • CGPathRef
  • CGImageRef
  • UIImage
  • NSString, with format or without
  • id

Implementing snapshotting for your custom classes

You can implement custom debug image:

- (UIImage*)kzp_debugImage;

If you have already implemented - (id)debugQuickLookObject that returns any of types supported by the KZPShow, you don’t need to do anything.

Controls

  • Button
KZPAction(@"Press me", ^{
// Magic code
})
  • Images

Picking an image from the library:

KZPAdjustImage(myImage);
KZPWhenChanged(myImage, ^(UIImage *img) {
  imageView.image = img;
});
  • Values
KZPAdjustValue(scale, 0.5f, 1.0f) //- for floats
KZPAdjustValue(position, 0, 100) //- for integers

you can also set default values:

KZPAdjustValue(position, 0, 100).defaultValue(50)
  • Block callbacks KZPAdjust are also available.

Animations

  • Block animation callback, code that will be executed with each screen refresh (display link). Useful for animating multiple values.
KZPAnimate(CGFloat from, CGFloat to, void (^block)(CGFloat));
KZPAnimate(void (^block)());
  • Auto-animated values, defines new variable and automatically animates them. AR -> AutoReverse
KZPAnimateValue(rotation, 0, 360)
KZPAnimateValueAR(scale, 0, 1)

Coordinating code execution

Executing code only once the value is set

KZPWhenSet(myImage, ^(UIImage *img) {
	//! magic
});

Executing code on value changes

KZPWhenChanged(myImage, ^(UIImage *img) {
	//! magic
});

Storing variables

Transient - Cleared with each code change

Instead of using instance variables / properties for KZPlayground class (you are fine to use them for normal classes that you create as part of playground), you should store playground specific variables that you need to reference between playground methods, eg. view you want to pan with UIPanGestureRecognizer inside transientObjects dictionary.

self.transientObjects[@"pannableView"] = view;

Persisted - Not cleared with recompilation

Implement setup method and use normal instance variables to store data you don't want to change on code change. eg. if you need to do some expensive operation.

Snapshots recorded during setup will persist in timeline.

- (void)setup
{
	self.data = [self fetchBigDataSet];
}

Installation and setup

KZPlayground is distributed as a CocoaPod: pod 'KZPlayground' so you can either add it to your existing project or clone this repository and play with it.

Remember to not add playgrounds in production builds (easy with new cocoapods configuration scoping).

Once you have pod installed, you need to create your playground, it’s simple:

  1. Subclass KZPPlayground
  2. Implement run method
  3. Conform to KZPActivePlayground protocol
    You can have many playgrounds in one project, but only one should be marked as KZPActivePlayground. It will be automatically loaded.
  4. present [KZPPlaygroundViewController playgroundViewController]

To apply your changes you have 2 approaches:

  1. Xcode/Appcode you can use cmd/ctrl + x (done via dyci plugin) while you are modifying your code.
  2. (My Preferrence) Automatic on file save (IDE agnostic) using kicker gem in terminal: (N.B. you need to have the kicker gem installed, see below)
kicker -sql 0.05 FOLDER_WITH_SOURCE_FILES

in case of Example project you'd call kicker from inside the project root folder (one containing the .kick file, which you will also need.)

kicker -sql 0.05 Example

This will react to all changes in .m files in the Example directory and reload your playground.

(Optional) Make Kicker autostart whenever you run your project

  1. Copy the .kick file to your project's directory.
  2. Add a new "Run Script" under your target's "Build Phases" tab with the following:
PID_PATH=/tmp/${PROJECT_NAME}_kicker.pid
if [ -e $PID_PATH ]
then
  kill $(cat $PID_PATH)
  rm $PID_PATH
fi
kicker -sql 0.05 . > /dev/null 2>&1 & echo $! > $PID_PATH

Note: You will need to manually kill the kicker process when you're done since it won't be killed after you stop running your project.

Only once

KZPlayground is powered by Code Injection, currently using Dyci code injection tool, you only need to install it once on your machine (You’ll need to reinstall it on Xcode updates):

git clone https://github.com/DyCI/dyci-main.git
cd dyci-main/Install/
./install.sh

In order to use the kicker gem, you need to install it as follows:

(sudo) gem install kicker

Swift support

My playgrounds now support Swift code, to use that you should use injectionforxcode instead of Dyci, make sure to grab 0.4 Release for some simpler API.

Contributing

Pull-requests are welcomed.

Changelog

0.4

  • Basic Swift support
  • Added Swift example

0.3.2

  • Ability to hide timeline

0.3.1

  • XCAsset images picking.
  • Persisting selected images.

0.3.0

  • Image picking.
  • Synchronisations.
  • Change observing.
  • Localizable strings are injected.

0.2.5

  • Persistent setup functionality.
  • Improved snapshots details.

0.2.0

  • All files in the project can be now changed to trigger playground reload.
  • Better kicker setup.
  • Transient objects.

License

KZPlayground is available under the modified MIT license. See the LICENSE file for more info.

Author

Krzysztof Zablocki, [email protected]

Follow me on twitter.

Check-out my blog or GitHub profile for more cool stuff.

Cool usages

Check out AudioKit examples using playgrounds

Attribution

SceneKit example code has been taken from David Ronnqvist upcoming SceneKit book, recommended.

Comments
  • compile error

    compile error

    Hi Krzysztof,

    I came across your library, and it seems great, but i am having some trouble making it work.

    I get the following error from kicker

    Couldn't load index file '/Users/Lena/.dyci/index/a3786fe6a1527268bf426a811b5b0718' ("/Users/Lena/Dev/TestProjects/iOS/testxibstoryboard/testxibstoryboard/Playground.m"). Use default compilation instead

    Failed (1) KZPlayground: Recompiled Playground.m

    Do you know why it doesnt compile and how to fix it?

    opened by pikaboo 10
  • Couldn't load index file Error

    Couldn't load index file Error

    Hi I'm trying this out, running the example folder. Hitting control x in xcode produces the following error however

    Failed to inject code

    Couldn't load index file '/Users/mtozer/.dyci/index/70b499f71e53e5ffce02104efdbdc3f4' (/Users/mtozer/code/fbobjc/VendorLib/KZPlayground/Example/KZPlayground/KZPlaygroundExample.m). Use default compilation instead

    Have you seen this before?

    opened by mathieutozer 6
  • Initial support for NSArray visualisation

    Initial support for NSArray visualisation

    I wrote code for the array support. It is not final, i just want to check that i'm going in the correct direction.

    For now it is able to show the array and the contained objects.

    opened by lucabartoletti 3
  • Example playground doesn't dynamically refresh in Xcode 6.3/iOS 8.3?

    Example playground doesn't dynamically refresh in Xcode 6.3/iOS 8.3?

    Hi, KZPlayground looks so awesome, thank you for it!

    I'm running KZPlaygroundExample in Xcode 6.3 but when I comment/uncomment some of the code in samplePlayground and save, the iOS Simulator doesn't seem to be refreshing itself as in your demo video. Maybe it's something with my environment, for example I saw this message in the debugger:

    DYCI directory path is : /Users/myusername/.dyci
    

    but that directory didn't exist, so I created it, but it didn't seem to make a difference. Any ideas on why it wouldn't be dynamically refreshing?

    Thanks again!

    opened by taberrr 2
  • KZP storyboard clashes with the

    KZP storyboard clashes with the "Main" storyboard of the actual app

    Upon trying to integrate the playgrounds into our app to play with it, I realized that the app loaded right into the "Main" storyboard of KZPlayground, instead of the one the app itself uses, which incidentally goes by the same name "Main".

    Looking at the code, KZPlayground is supposed to be loading the storyboard from the [NSBundle bundleForClass:self], but somehow it doesn't seem to be in another bundle, since the wrong storyboard is used to initialize the app.

    I have no clue about NSBundle and especially not in combination with CocoaPods, but a quick solution would be to avoid the "Main" name for KZPlayground's storyboard :smile:

    opened by leberwurstsaft 2
  • Swift support

    Swift support

    My playgrounds now support Swift code, to use that you should use injectionforxcode instead of Dyci, make sure to grab 0.4 Release for some simpler API.

    Cocoapods doesn't have 0.4 pushed. Is the package supposed to be installing injection like the 0.3 version? Or is that meant to be a manual extra feature?

    opened by goktugyil 1
  • Injection attempting connection to: 127.0.0.1:31442

    Injection attempting connection to: 127.0.0.1:31442

    Hi,

    I have removed the KZPlayground from the project but it still shows "Injection attempting connection to: 127.0.0.1:31442" in console ,How do i remove this log too ?

    Thanks, Ian

    opened by ianwhite2 1
  • Kicker recipe will fail if any of directories contain space character.

    Kicker recipe will fail if any of directories contain space character.

    I had issue with kicker failing on directory that contains space character in its name.

    execute("/usr/bin/python #{File.expand_path("~/.dyci/scripts/dyci-recompile.py")} #{"\"%s\"" % File.expand_path(file)}")
    

    Replacing execute command in .kick file with the one above should fix it. The only difference is that I added quotation marks surrouding the file path using string format operator.

    opened by pawel-sekara 1
  • Makes KZPlaygournds work with injectionforxcode!

    Makes KZPlaygournds work with injectionforxcode!

    Hi Krzysztof, Very impressed with KZPlaygrounds but can’t believe I didn’t do this before now. If you add these three lines you can use injection without the dyci setup. Cheers, John

    opened by johnno1962 1
  • Rename project to non-offensive name

    Rename project to non-offensive name

    As a German, the name of this project sends chills up my spine: https://en.wikipedia.org/wiki/Nazi_concentration_camps

    I really like the idea behind this project, would you consider renaming it?

    opened by pcomans 1
  • update readme for kicker gem

    update readme for kicker gem

    Hi Krzystof, as per our conversation earlier, I modified readme to include the kicker gem install. I would also recommend putting the install and setup instructions at the very top of the readme, as this seems to be the standard. let me know if you want me to modify the readme like that! cheers Brio

    opened by briomusic 0
Owner
Krzysztof Zabłocki
Making Swift engineers more efficient through tools and workflows.  My code powers up over 70 000+ apps.
Krzysztof Zabłocki
Model2App - Turn your Swift data model into a working CRUD app.

Model2App is a simple library that lets you quickly generate a CRUD iOS app based on just a data model defined in Swift. (CRUD - Create Read Update De

Q Mobile 132 Dec 22, 2022
MisterFusion is Swift DSL for AutoLayout. It is the extremely clear, but concise syntax, in addition, can be used in both Swift and Objective-C. Support Safe Area and Size Class.

MisterFusion MisterFusion makes more easier to use AutoLayout in Swift & Objective-C code. Features Simple And Concise Syntax Use in Swift and Objecti

Taiki Suzuki 316 Nov 17, 2022
STPopup provides STPopupController, which works just like UINavigationController in popup style, for both iPhone and iPad. It's written in Objective-C and compatible with Swift.

STPopup STPopup provides STPopupController, which works just like UINavigationController in popup style, for both iPhone and iPad. It's written in Obj

Kevin Lin 2.6k Jan 6, 2023
ViperC - Xcode template for VIPER Architecture for both Objective-C and Swift.

ViperC Xcode template for VIPER Architecture for both Objective-C and Swift. ViperC creates modules for you when you want to use VIPER architecture in

Abdullah Selek 79 Nov 2, 2022
A script for focusing on work, blocking non-work stuff.

A script for focusing on work, blocking non-work stuff. The idea is to forbid mindless app/website context-switching while you're focused. Once you're

null 3 Jan 23, 2022
Work-hours-mac - Simple app that tracks your work hours from the status bar

Track Your Work Hours Simple app that tracks your work hours from status bar. Fe

Niteo 44 Dec 2, 2022
JSPatch bridge Objective-C and Javascript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. JSPatch is generally used to hotfix iOS App.

JSPatch 中文介绍 | 文档 | JSPatch平台 请大家不要自行接入 JSPatch,统一接入 JSPatch 平台,让热修复在一个安全和可控的环境下使用。原因详见 这里 JSPatch bridges Objective-C and JavaScript using the Object

bang 11.4k Jan 1, 2023
The better way to deal with JSON in Objective-C (inspired by SwiftyJSON)

NSTEasyJSON Inpired by SwiftyJSON. NSTEasyJSON makes it easy to deal with JSON data in Objective-C. Why is the typical JSON handling in Objective-C NO

Timur Bernikovich 11 Apr 2, 2020
A library and tool for interacting with both the local and remote asset caches.

Asset Cache Tool A library and tool for interacting with both the local and remote asset caches. This is based on research I did a few years ago on th

Kenneth Endfinger 20 Dec 23, 2022
A micro-framework for observing file changes, both local and remote. Helpful in building developer tools.

KZFileWatchers Wouldn't it be great if we could adjust feeds and configurations of our native apps without having to sit back to Xcode, change code, r

Krzysztof Zabłocki 1k Dec 19, 2022
🔍BarcodeScanner – simple & easy application that helps you to scan both EAN8 and EAN13 barcodes.

?? Simple & easy application that helps you to scan both EAN8 and EAN13 barcodes.

Tamerlan Satualdypov 16 Apr 22, 2022
iOS-based charting library for both line and bar graphs.

JBChartView Introducing JBChartView - Jawbone's iOS-based charting library for both line and bar graphs. It is easy to set-up, and highly customizable

Jawbone 3.8k Jan 1, 2023
iOS routing done right. Handles both URL recognition and controller displaying with parsed parameters. All in one line, controller stack preserved automatically!

Developed and Maintained by Ipodishima Founder & CTO at Wasappli Inc. (If you need to develop an app, get in touch with our team!) So what is this lib

null 589 Dec 24, 2022
:droplet: A generic view model for both basic and complex scenarios

Brick Description Brick is a generic view model for both basic and complex scenarios. Mapping a basic table view cells is as easy as pie, if you have

HyperRedink 59 Jul 31, 2021
A platform where NYUAD students can both Help and Seek Help.

A platform where NYUAD students can both Help and Seek Help.

Omar Rayyan 0 Nov 7, 2021
iOS's Stocks App clone written in React Native for demo purpose (available both iOS and Android).

FinanceReactNative iOS's Stocks App clone written in React Native for demo purpose (available both iOS and Android). Data is pulled from Yahoo Finance

kf 2k Dec 29, 2022
Check and update app's version for both AppStore & Fir

VersionUpdate Check and update app's version for both AppStore & Fir How to use Add Channel in info.plist Now we only support two channels "AppStore"

倪敏杰 5 Jan 15, 2021
A basic iOS app that takes input from the user, displays it, allows changing both text color and background color.

Hello-iOSApp App Description A basic iOS app that takes input from the user, displays it, allows changing both text color and background color. App Wa

null 0 Jan 8, 2022
A simple way of doing both symmetric and asymmetric crypto without the headache

Simple Swift Crypto I needed a simple way of doing both symmetric and asymmetric

Joe Hinkle 6 Dec 19, 2022
BDD Framework and test runner for Swift projects and playgrounds

Spectre Special Executive for Command-line Test Running and Execution. A behavior-driven development (BDD) framework and test runner for Swift project

Kyle Fuller 392 Jan 1, 2023