[TIMOB-23812] Hyperloop: UIColor type properties is not working with Xcode 8 beta
GitHub Issue | n/a |
Type | Bug |
Priority | Critical |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2016-09-09T13:59:17.000+0000 |
Affected Version/s | Release 5.5.0 |
Fix Version/s | Release 5.5.0, hyperloop 1.2.7 |
Components | Hyperloop, iOS, Tooling |
Labels | qe-5.5.0 |
Reporter | Josh Longton |
Assignee | Jan Vennemann |
Created | 2016-08-23T23:35:05.000+0000 |
Updated | 2016-09-15T18:20:22.000+0000 |
Description
In Xcode 8 beta 6 on the build of the application the instance of redColor
is generated but not the class.
Steps to reproduce:
Download the Xcode beta
Select to use the beta version of Xcode xcode-select -s <xcode beta location>
Create a new application with hyperloop
Use the app.js below in the application
appc run -p ios
Select to use the GA version of Xcode xcode-select -s <xcode GA location>
appc run -p ios
App.js
{noformat}
var UIView = require('UIKit/UIView'),
UIColor = require('UIKit/UIColor'),
UIImage = require('UIKit/UIImage'),
CGRectMake = require('CoreGraphics').CGRectMake;
var win = Ti.UI.createWindow({
backgroundColor: 'white',
layout: 'vertical'
});
var view = UIView.alloc().initWithFrame(CGRectMake(10, 10, 50, 50));
view.backgroundColor = UIColor.redColor();
win.add(view);
win.open();
{noformat}
Actual when using Xcode 8 beta 6
{noformat}
[ERROR] Script Error {
[ERROR] column = 40;
[ERROR] line = 11;
[ERROR] message = "UIColor.redColor is not a function. (In 'UIColor.redColor()', 'UIColor.redColor' is undefined)";
[ERROR] sourceURL = "file:///Users/Josh/Library/Developer/CoreSimulator/Devices/D5EEC5AB-078C-46AA-AC55-05BBBD410CB7/data/Containers/Bundle/Application/6680ADD3-DB71-4F72-8610-D837D5476666/Hyperloop%20forward%20testing.app/app.js";
[ERROR] }
{noformat}
Expected
The application runs as it does in Xcode 7.3.1
Comments
JSON Source
I will investigate this issue to see if anything else have been affected in the Xcode beta.
I helped Josh trouble shoot. It looks like based on the HL code gen output that in the newer SDK UIColor redColor is now both +[UIColor redColor] and -[UIColor redColor] and the generation (JS) only generates the instance and not both the instance and the class methods.
Yep, Xcode 8 introduced the color-properties to (probably) ease the syntax on the Obj-C side - which also generates the property getter / class method.
They seem to use the also in Xcode 8 introduced
UIKIT_DEFINE_AS_PROPERTIES
statement to switch between the (class)-property and class-method usage. So in this case, the above statement seems to be true and so the usual class-methods as we know them are not even compiled by iOS. Bonus: The statement is defined as the following:So we may need to investigate if it makes sense to make it *a)* detect the define and property automcatically or *b)* stick to the "old" behavior for now.
So the main problem here is that Hyperloop does not differentiate between instance and class properties. As Jeff already pointed out, it recognizes the property but treats it as an instance property, thus resulting in wrong code generated in the JS files. I'll update the metabase generator and the templates to also support the new class level properties.
WIP PR: https://github.com/appcelerator/hyperloop.next/pull/65 Here is what i have so far, but now i've run into a bug in libclang (well, at least i think its a bug). As said before, the idea is to detect if a property is a class property and generate the matching js code in this case. We use
clang_Cursor_getObjCPropertyAttributes
to read the attributes defined on a property. The thing is, as soon as the property contains theclass
attribute this function will always returnCXObjCPropertyAttr_noattr
. Meaning we have no way to detect if a property is a class property or not. Any ideas how to workaround this are greatly appreciated :)*sigh* Turns out the rpath build setting was hardcoded to the Xcode 7 toolchain directory and therefore loading the wrong version of libclang causing this unexpected behaviour. Changed it to use the currently selected Xcode version using
$(DEVELOPER_DIR)
, works like a charm now. PR updated and ready for review, [~hansknoechel] PR: https://github.com/appcelerator/hyperloop.next/pull/65 PR (1.2.X): https://github.com/appcelerator/hyperloop.next/pull/66Ok, so the PR works. However, we now cannot use the known syntax
UIColor.redColor()
anymore, onlyUIColor.redColor
(property instead of method). I see this as a breaking change in Hyperloop, so we should be very cautious integrating is change. If possible, couldn't we "just" support both and generate a util-method that creates both the JS method and property? Thoughts?we should support both class and instance properties. both are legal in JS
The PR does exactly that. I compared with the normal instance property UILabel.text today and this property works exactly the same. You can use
label.text
but notlabel.text()
. As Hans said this is a breaking change in the UIColor api (and other classes that switched to class properties) on our side because of the way objc properties work. Through the property synthesize process in objc nothing changes as the getter/setter methods replace the removed class methods. In JS we can only either use the property or the method but not both. I'm currently looking into wether we could improve the usage detection so usingUIColor.redColor()
would cause the method to be generated andUIColor.redColor
would trigger the property to be generated.Ok, for now i updated the [1.2.X PR](https://github.com/appcelerator/hyperloop.next/pull/66) with a simple but not really elegant workaround to maintain api compatibility. We just check against a list of predefined properties (all that are new in iOS 10 because of the
UIKIT_DEFINE_AS_PROPERTIES
andFOUNDATION_SWIFT_SDK_EPOCH_AT_LEAST(8)
macros) and generate the getter method rather than the property if it is in this list. I'm not really happy with this solution as we would have to maintain the list of properties if anything changes in future iOS SDKs (Script to detect properties affected by the macros: https://gist.github.com/janvennemann/380dde99ef9aa96c6d4a990bee520642). However, there is currently no other way to determine which properties are generated because of those two macros. Referring to my last comment, we could detect if someone usesUIColor.redColor()
orUIColor.redColor
and then either generate the appropriate method or property. Using the method and property simultaneously could result in a build error stating to use either of them but not both. The question is if we want to invest more time on this or just remove the workaround in a future version of Hyperloop and introduce the new api based on properties?[~jvennemann] [~hansknoechel] Ok so I spoke with Ingo. We have agreed to go ahead with this PR for the sdk 5.5.0 release. And the proposal is to remove the workaround in Hyperloop 2.0.0 (Ti SDK 6.0.0) and introduce the new api based on properties. So let's get started on testing this PR asap and get a 1.2.7 up.
Did a simple FT. For this to work, if you have 2 Xcodes installed, please remember to
sudo xcode-select --switch /Applications/Xcode-GM.app
before doing a./build.sh
After you install the built module, if you do *appc run -p ios -I 10.0* on hyperloop-examples, it works flawlessly. However, if you do *appc run -p ios -I 9.3* on hyperloop-examples, it will fail with[ERROR] Unable to find Info.plist in root of specified app path: /Users/kiat/titaniumModules/hyperloop-examples/build/iphone/build/Products/Debug-iphonesimulator/Hyperloop_Sample.app/Info.plist
And it's true, it's missing. weird! Here is why. Hyperloop metabase generation is entirely dependent on the pre-selected Xcode. It's not dependent on the-I 10.0
flag. Here are the rules for Hyperloop to work in the scenario where you have 2 Xcodes existing. 1.sudo xcode-select --switch /Applications/Xcode-GM.app
followed byappc run -p ios -I 10.0
2.sudo xcode-select --switch /Applications/Xcode.app
followed byappc run -p ios -I 9.3
If you mix up this combination, the build will fail with various types of errors, such as the missing info.plist. I am ok to put this in the release notes as "how to use hyperloop if you have 2 versions of Xcode installed" if we can't fix this in the short time we have. (considering QE still needs to test this)PR approved & merged! [~jvennemann] Please file an own ticket for the bad-access crashes when using classes in a certain edge-case scenario. Thanks!
Verified fixed, using: MacOS 10.12 (16A313a) Studio 4.7.1.201609100950 Ti SDK 5.5.0.GA Appc NPM 4.2.7 Appc CLI 5.5.0 Alloy 1.9.2 Xcode 8.0 (8A218a) UIColor type properties can be used via the
UIColor.<color>Color()
methods with Xcode 8 GA without error. Accessing the properties by actual instance propertiesUIColor.<color>Color
fails, but that should be covered in Hyperloop 2.0.0, as Kiat mentioned above. Tested using the provided sample code as well as using the UIColor methods in other test apps.