rightpoint / eject Goto Github PK
View Code? Open in Web Editor NEWAn eject button for Interface Builder to generate swift code
License: MIT License
An eject button for Interface Builder to generate swift code
License: MIT License
IB has segmentControlStyle
which has no mapping to code. The error should be swallowed.
Code generation is not correct. There's also some curious double-nesting in xib files when created fresh, ie:
<visualEffectView opaque="NO" contentMode="scaleToFill" id="JqZ-8z-GcL">
<rect key="frame" x="0.0" y="0.0" width="240" height="128"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="qar-2Q-g4b">
<frame key="frameInset"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<visualEffectView opaque="NO" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oio-Xx-v59">
<frame key="frameInset"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" ambiguous="YES" id="AIi-sS-Vsr">
<frame key="frameInset"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</view>
<vibrancyEffect>
<blurEffect style="light"/>
</vibrancyEffect>
</visualEffectView>
</subviews>
</view>
<vibrancyEffect>
<blurEffect style="light"/>
</vibrancyEffect>
<point key="canvasLocation" x="326" y="485"/>
</visualEffectView>
Wonder if the view hierarchy that's created is as strange as the XML looks.
If anyone has opinions on how to generate code for segues, please reply here!
What's the license for this project?
I currently disable frame generation all together. The choice should be deferred to the .xib
file instead of a configuration option since it's a flag on the document.
It would be nice to syntax-highlight the generated Swift code on the page.
It would be better if UIBarButtonItem
would inject the target action pair instead of having an additional configuration line.
Just a thought but what if, as a user, I could:
Code like this:
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor(white: 1, alpha: 1)
let button = UIButton(type: .roundedRect)
button.titleLabel?.lineBreakMode = .byTruncatingMiddle
button.isOpaque = false
button.translatesAutoresizingMaskIntoConstraints = false
button.clipsToBounds = true
button.setContentCompressionResistancePriority(1, for: .vertical)
button.setTitle("Button", for: .normal)
view.addSubview(button)
contentView.addSubview(view)
would become...
extension UITableViewCell {
func decorate() {
let view = UIView()
view.setState_XcodeSpecificLabel_()
let button = UIButton()
button.setState_XcodeSpecificLabel1_()
view.addSubview(button)
contentView.addSubview(view)
button.setState_XcodeSpecificLabel2_()
}
}
extension UIView {
func setState_XcodeSpecificLabel_() {
translatesAutoresizingMaskIntoConstraints = false
backgroundColor = UIColor(white: 1, alpha: 1)
}
}
extension UIButton {
func setState_XcodeSpecificLabel1_() {
type = .roundedRect
titleLabel?.lineBreakMode = .byTruncatingMiddle
isOpaque = false
translatesAutoresizingMaskIntoConstraints = false
clipsToBounds = true
setContentCompressionResistancePriority(1, for: .vertical)
setTitle("Button", for: .normal)
}
}
extension UIButton {
func setState_XcodeSpecificLabel2_() {
type = .roundedRect
titleLabel?.lineBreakMode = .byTruncatingMiddle
isOpaque = false
translatesAutoresizingMaskIntoConstraints = false
clipsToBounds = true
setContentCompressionResistancePriority(1, for: .vertical)
setTitle("Button", for: .normal)
}
}
Pros
Cons
Eject models XML attributes to properties pretty well, but it does not model XML elements to properties very well. This usually just works, so it's not a big deal, but currently there's no way to inject a node value into the constructor. This is mostly causing issues for frame
, but also for passing in target actions into UIBarButtonItem.
Currently the CLI tool is very bare bones. It should have easy integration to manage the Configuration
struct.
Generating code for this will require generating methods. This shouldn't be too hard, but will require stencil. Ideas on how the code should be generated would be great!
There is a placeholder
key on constraint. I'm not sure what this actually does. Very often it won't have enough information to generate a valid constraint and can cause failures.
==> xcodebuild SYMROOT=build
Build settings from command line:
SYMROOT = build
note: Using new build system
note: Planning build
note: Constructing build description
error: SWIFT_VERSION '3.0' is unsupported, supported versions are: 4.0, 4.2, 5.0. (in target 'eject' from project 'Eject')
error: SWIFT_VERSION '3.0' is unsupported, supported versions are: 4.0, 4.2, 5.0. (in target 'EjectKit' from project 'Eject')
The current code generation is as simplistic as I could get away with. It should:
Stencil
to manage the high-level code structure.
Reference
button.lineBreakMode
should be button.titleLabel.lineBreakMode
The IB trait collection exclusion mechanism isn't implemented. This is mainly because I don't know how to generate code that wouldn't be terrible. Generating Relayout code is probably the current best option.
UICollectionView has a dataMode
that has no direct mapping to code. I believe this warning should just be swallowed.
When a UIDatePicker is created the minuteInterval is incorrect. It should be in Int.
open var minuteInterval: Int // display minutes wheel with interval. interval must be evenly divided into 60. default is 1. min is 1, max is 30
let timePicker = UIDatePicker()
timePicker.datePickerMode = .dateAndTime
timePicker.minuteInterval = .1
timePicker.translatesAutoresizingMaskIntoConstraints = false
This is up for review here
UIStackView is not always generating code in an order that is the same as represented in Interface Builder, causing some views to be misplaced after running through Eject.
There should be a button for one-click download of the generated Swift code as a .swift file.
I had a view that had layout margins as such:
<edgeInsets key="layoutMargins" top="0.0" left="10" bottom="0.0" right="10"/>
Unfortunately the layoutMargins
property was skipped over when generating the view's code.
The unit-tests accept the warning, but it should be fixed.
This will probably be one of the more complicated builders. I'd prefer we generate BonMot code.
<attributedString key="attributedText">
<fragment content="I agree that I have read and understand the ">
<attributes>
<color key="NSColor" red="0.58823529411764708" green="0.58823529411764708" blue="0.58823529411764708" alpha="1" colorSpace="calibratedRGB"/>
<font key="NSFont" size="12" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
</attributes>
</fragment>
<fragment content="terms & conditions">
<attributes>
<color key="NSColor" red="0.14117647058823529" green="0.59607843137254901" blue="0.54509803921568623" alpha="1" colorSpace="calibratedRGB"/>
<font key="NSFont" size="12" name="HelveticaNeue-Bold"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
</attributes>
</fragment>
</attributedString>
UISegmentedControl uses setTitle
instead of insertSegment(withTitle
. This causes a runtime crash.
verticalAnchors
, horizontalAnchors
, and edgeAnchors
should all be used if possible.
Add support for SnapKit
https://github.com/SnapKit/SnapKit
It was short sighted to use fatalError for parsing errors, the contract should throw.
So I build the project, navigate to the build directory in the terminal, then run ./eject
. This message spits out at me:
dyld: Library not loaded: @rpath/EjectKit.framework/Versions/A/EjectKit
Referenced from: /Users/edwardloveall/Library/Developer/Xcode/DerivedData/Eject-gcyocjdokcfabqevoqmiqqzavoxx/Build/Products/Debug/eject
Reason: image not found
zsh: abort
This is opposed to the generic help message that spits out into the xcode log when I build and run.
The color node doesn't have any context, it just uses the configured keyPath, which is wrong.
We can pretty easily override a universal keyPath mapping which would change all highlightedColor
keys in a color node to highlightedTextColor
. This would be more explicit ideally (ie: only do the mapping inside of labels), but in reality I think this simple hack should work fine.
I am interested in this just for the idea of being able to make a diff more readable of a XIB file. I was doing some work on this concept in the following gist. I think you could use a couple of other naming ideas like the ones I used here https://gist.github.com/drumnkyle/bf3f3b5acbb1199c7b6c0f00f396977b aside from just the userLabel.
So I ran Eject on my .xib and got this output:
document.objects.view.subviews.view: insetsLayoutMarginsFromSafeArea='NO'
document.objects.view.subviews.view: insetsLayoutMarginsFromSafeArea='NO'
Can not configure XML nodes 'viewLayoutGuide'
Can not configure XML nodes 'point'
Variable 'imageView: UIImageView' was generated 2 times. // <-- specific to my project
Error: invalidReference("2kL-IL-xdO")
It appears that the program is unable to support constraints against the safe area layout guide, added in iOS 11.
Here is the relevant source from the xib file:
// ...
<constraints>
<constraint firstItem="2kL-IL-xdO" firstAttribute="bottom" secondItem="Zi3-cc-4t5" secondAttribute="bottom" constant="20" id="8U4-yK-lhp"/>
<constraint firstItem="2kL-IL-xdO" firstAttribute="bottom" secondItem="3i5-rT-P9f" secondAttribute="bottom" constant="20" id="8Wl-FC-8aX"/>
<constraint firstItem="tBV-wJ-bHs" firstAttribute="leading" secondItem="2kL-IL-xdO" secondAttribute="leading" constant="16" id="DYw-JW-42g"/>
<constraint firstItem="2kL-IL-xdO" firstAttribute="trailing" secondItem="3i5-rT-P9f" secondAttribute="trailing" constant="20" id="FKk-5J-rwC"/>
<constraint firstItem="2kL-IL-xdO" firstAttribute="trailing" secondItem="iI4-J5-UpK" secondAttribute="trailing" constant="89" id="G2d-aF-bYk"/>
<constraint firstItem="Zi3-cc-4t5" firstAttribute="leading" secondItem="2kL-IL-xdO" secondAttribute="leading" constant="20" id="Kas-ql-tKM"/>
<constraint firstItem="tBV-wJ-bHs" firstAttribute="top" secondItem="5C9-QY-uP2" secondAttribute="bottom" constant="-1" id="KoW-CI-mIs"/>
<constraint firstItem="W73-W8-5S3" firstAttribute="centerX" secondItem="2kL-IL-xdO" secondAttribute="centerX" id="KrG-m9-qvT"/>
<constraint firstAttribute="trailing" secondItem="YHR-GC-tiW" secondAttribute="trailing" id="LdH-1r-g0g"/>
<constraint firstItem="5C9-QY-uP2" firstAttribute="top" secondItem="ADU-wZ-6Mx" secondAttribute="bottom" constant="14" id="QjB-0e-Cdv"/>
<constraint firstItem="ADU-wZ-6Mx" firstAttribute="leading" secondItem="2kL-IL-xdO" secondAttribute="leading" id="R8u-cw-6KD"/>
<constraint firstAttribute="bottom" secondItem="YHR-GC-tiW" secondAttribute="bottom" id="Tf1-zr-ncU"/>
<constraint firstItem="iI4-J5-UpK" firstAttribute="top" secondItem="2kL-IL-xdO" secondAttribute="top" constant="45" id="UQW-Lt-gTE"/>
<constraint firstItem="ADU-wZ-6Mx" firstAttribute="top" secondItem="W73-W8-5S3" secondAttribute="bottom" constant="8" id="YKH-bV-GFb"/>
<constraint firstItem="YHR-GC-tiW" firstAttribute="top" secondItem="977-Kl-DqP" secondAttribute="top" id="YaX-ba-BQb"/>
<constraint firstItem="2kL-IL-xdO" firstAttribute="trailing" secondItem="tBV-wJ-bHs" secondAttribute="trailing" constant="16" id="Ycl-6J-UBO"/>
<constraint firstItem="iI4-J5-UpK" firstAttribute="leading" secondItem="2kL-IL-xdO" secondAttribute="leading" constant="90" id="e8a-kC-VxY"/>
<constraint firstItem="YHR-GC-tiW" firstAttribute="leading" secondItem="977-Kl-DqP" secondAttribute="leading" id="h0W-Wq-OnG"/>
<constraint firstItem="2kL-IL-xdO" firstAttribute="trailing" secondItem="ADU-wZ-6Mx" secondAttribute="trailing" id="klO-yT-vIA"/>
<constraint firstItem="W73-W8-5S3" firstAttribute="top" secondItem="iI4-J5-UpK" secondAttribute="bottom" constant="27" id="lAV-H5-8eZ"/>
<constraint firstItem="3i5-rT-P9f" firstAttribute="top" relation="greaterThanOrEqual" secondItem="tBV-wJ-bHs" secondAttribute="bottom" id="pJ9-Cb-772"/>
<constraint firstItem="2kL-IL-xdO" firstAttribute="trailing" secondItem="5C9-QY-uP2" secondAttribute="trailing" constant="16" id="pUr-Fw-BIK"/>
<constraint firstItem="iI4-J5-UpK" firstAttribute="centerX" secondItem="2kL-IL-xdO" secondAttribute="centerX" id="rbI-JP-9gZ"/>
<constraint firstItem="5C9-QY-uP2" firstAttribute="leading" secondItem="2kL-IL-xdO" secondAttribute="leading" constant="16" id="wE1-MW-VkO"/>
</constraints>
// ...
<viewLayoutGuide key="safeArea" id="2kL-IL-xdO"/>
// ...
This is all under the root view in the hierarchy.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.