Swift compiler slow - why does it always recompile classes with an extension? - swift

we've been having problems with very slow compile time on our rather big projects. Based on this great article: https://thatthinginswift.com/debug-long-compile-times-swift/ I set my swift compiler flags to:
-Xfrontend -debug-time-function-bodies
and started debugging. What I found out was that for every file that is compiled (>200) it also compiles bunch of seemingly unrelated files with it.
After more debugging it seems that if you add to a class or struct any extension like this:
extension MasterViewController {
func someFunc(){
}
}
the class MasterViewController will be compiled with any unrelated file in your target.
In my small example project there is also DetailViewController which is pushed from the MasterViewController. Because MasterViewController has referenced it, it also have to be recompiled with it. Every time for every file.
On this small project, the compile time is still fast but you can see how this can get really slow on big project where the extensions are used in more than few classes. On our project more than half of the source files is recompiled every time.
To test out the issue download the CompilerTest project from here https://1drv.ms/u/s!Av6oIon-UawdxmUtmDCNWF_zOcjn
Then build the project and go to latest build in Report navigator. After expanding the TestFile.swift you will see that MasterViewController was also compiled even though its not referenced at all in the file.
Then comment out the extension in MasterViewController.swift, clean the project and build folder. Then build again. You will see that the TestFile is now compiled as it should.
My question is whether there is a reason for this behaviour or if it is a bug that should be reported.

Related

Xcode builds app correctly, but unable to launch?

I'm running 10.10 with Xcode 6.1.
And I'm having trouble getting an app I wrote to work. After hours and hours I finally got it to build correctly after accidentally messing with something, but now I'm getting an error I don't have permission to view the file (if I open directly in Xcode) or if I try to open it from the Finder it says the App is damaged or corrupt and can't be open. If it matters it's written in Swift.
I've literally spent 6 hours on this (Just trying to get it to build) so any help would be greatly appreciated! Austen
Here's the Xcode workspace, project, files, and a build if anyone needs to take a look: http://pattersoncode.ca/ServerChecker.zip
There are a several issues here. I can't help you with all of them, but I can put you on the right path, at least.
The app won't launch because it wasn't built correctly. Specifically, there's not any actual binary executable in the built .app. You can see this by right-clicking on the built Server Checker.app and choosing Show Package Contents. In there is a Contents folder; open that. Inside that should be a folder called MacOS, in which your actual binary executable would be. But it's not there. This isn't really an app at all.
Reason is, you have a custom build rule for swift files that's making them not compile at all. Just remove that, you don't need it.
In Xcode, click on the top-level item of the project (it says something like ServerChecker, 1 target, OS X SDK 10.10). Then, under TARGETS, select ServerChecker. Click Build Rules. The thing that says "Swift source files using Script", that we don't need. Click the little X in the top-right corner, and click Delete when prompted. Now try to build again.
You'll get an error:
Undefined symbols for architecture x86_64:
"_main", referenced from:
implicit entry/start for main executable
Since you don't have a main.swift file, your app doesn't have a main entry point. In Swift, you must either provide an NSApplicationMain function (usually in main.swift), or you can declare your app delegate as NSApplicationMain, which has the effect of calling NSApplicationMain with your delegate class. I recommend the latter.
Open up AppDelegate.swift, and add #NSApplicationMain to your AppDelegate class. It should look like:
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
...
}
Now your app should build again. Right-click it and Show Package Contents to verify that there's actually an executable binary in there.
The app still won't run. It looks like on launch there's an error that a library couldn't be loaded.
Hopefully that helps you get moving, anyway. I really need to get back to work now. :)

Can Swift playgrounds see other source files in the same project?

I created the most simple custom class in a separate Swift file in my project:
class Foo
{
init()
{
println("I made a foo.")
}
}
Then, in a playground within the same project, I tried
var x = Foo()
Xcode didn't seem to like this, and told me that 'Foo' is an unresolved identifier. I'm somewhat confused about how playgrounds fit into the rest of the project structure, since any other Swift file in my project can resolve 'Foo' without issue.
How can I make my playground able to use custom classes I define in other Swift files in my project? I have tried naming the product module for the build target and importing that into the playground, with no success: the playground doesn't recognize the name of the product module.
Thanks in advance for the assistance. I know it is something simple.
There's two ways to use your project's code in a Playground
Playground's Sources Folder
Yes, in Xcode 6.3 Beta 3 (and hopefully, into the future):
Playgrounds are now represented within Xcode as a bundle with a disclosure triangle that reveals Resources and Sources folders when clicked. These folders contain additional content that is easily accessible from your playground’s main Swift code. To see these folders, choose View > Navigators > Show Project Navigator (or just hit Command-1).
Open up a new playground and hit cmd + 1 to see the left pane, then drag files into the source folder to use within the playground.
Note:
The files in the source folder are compiled to a framework which means if you want classes, functions, etc. to be accessible in the playground, they must be explicitly marked as public.
public class VisibleClass {
}
class InvisibleClass {
}
Source: release blog
Compile Project Into Framework
Move project to workspace if it isn't already. (File -> Save as Workspace) will do the trick
Add framework target to your project
Build framework
Make sure files you want to access are added to your framework target
Add Playground to workspace (NOT the project)
Use #testable import YourFrameworkName
Access code in playground
I made a write up here that goes into a bit more detail if you want to check it out.
They cannot. Playgrounds are self-contained. This will hopefully change in the future.
Edit: As of Xcode 6.3, Playgrounds can now contain supporting code. They still cannot see other code in the same project, but code can be added to the support folder of a Playground that can be used from within the playground. See the Swift blog for more info.
Yes.
I started by just adding a class file in the Sources directory.
I made everything public:
class
init
members
After much trying, nothing worked. The XCode crashed and after reopening it all worked like a charm.
In Xcode 10's Project Navigator:
Add the source code file to the playground's Sources folder.
Drag the file from the playground's Sources folder to the desired location in the project (you should see the little "plus in a circle" icon appear.
End the drag and then in the Add File dialog uncheck "copy if needed"
The source file now "lives" in the playground package; the Project refers to it (you can verify that with the File Inspector).
I tried it the other way around: file lives in project folder with reference in playground's Sources folder but it didn't work; I ended up with two copies of the source code file.

Cannot compile my app with few classes from the Google Mac Toolbox

UPDATE:
Here is more detailed compiler output:
So I am working on a simple app. I want to be able to do some encoding/decoding of strings, so I have added these three files from the Google Mac ToolBox to my project:
GTMDefines.h
GTMNSString+HTML.h
GTMNSString+HTML.m
Since my project uses ARC, I have added the files to the build phases and set the -fno-objc-arc flag so they don't compile with ARC. See the screenshot:
Now I go to my main view controller and add this line:
#import "GTMNSString+HTML.m"
And I try to compile my project. I get errors like these:
How can I solve this? I am new to iOS development so please explain well.
To get rid of the first two warnings (no rule to process file...) remove GTMDefines.h and GTMNSString+HTML.h from your "Compile sources". Only .m-files need to be there.
You never want to import .m files, even if it's technically possible! To get rid of your errors, change your import from
#import "GTMNSString+HTML.m"
to
#import "GTMNSString+HTML.h"

Xcode 4.1 sudden strange compile behaviour after crash

I've suddenly got a very weird error in Xcode 4.1 that seems to have occurred after Xcode crashed.
I have some Model classes that inherit from a simple base class. Nothing unusual there.
What's happening now is that when I attempt to build for the "device" for one of these model classes that inherit (and only one) it throws a bunch of compile errors saying blah blah undeclared etc. Now if I switch it back to the simulator it builds and runs fine.
This was working perfectly well before the crash. I've done all of the usual clean build, delete derived data, restart XCode etc but still I can't make it work.
If I explicitly add the various bits from the base class into this problematic class it all works fine again.
I'm really perplexed. Any suggestions?
Thanks in advance,
Matt
You should try a "Product->Clean" and then recompile.
Sometimes Xcode doesn't seem to recognize changes made to files and gives weird errors and warnings.
Hope this helps.
If MrHus' clean doesn't work, Control-Click on your .xcodeproj and select Show Package Contents (Xcode projects are bundles). Remove everything but the project.pbxproj files; they may be corrupt.
If that doesn't work, try creating a whole new project from scratch. If that works, then your project.pbxproj was corrupt.

Rename a class in Xcode: Refactor... is grayed out (disabled). Why?

Why is Refactor... grayed out (disabled) in Xcode?
I'd like to rename a class.
Select the class's symbol in its header file - i.e. the bit just after #interface. Then the refactoring stuff should be enabled.
If you are using Objective-C++ (i.e. mix Objective-C with C++ code) then refactoring is disabled in xcode since it does not support refactoring of C++ code.
Refactor might also be disabled if affected files (most likely the file with your class in it) are not saved.
I've been using Xcode for 5 years now, and refactoring has never worked correctly (even xcode 4.6 has major bugs where it WILL corrupt your source code!).
The workaround has always been (still works 100%, even in cases where Apple's code fails)
use shift-command-f to find all uses of the file
select "replace" in the search settings
"replace-all"
do the following for the .h file, and REPEAT IT FOR THE .m FILE (if you have one):
right click the original file, and select "show in finder"
delete the file from xcode (select "delete references only" when asked)
rename the .h (and .m if you have one) in Finder
in Xcode, select "Product -> (hold down Alt) -> Clean Build Folder"
quit xcode (you can usually get away with not doing this - but NOTE: there are some other MAJOR bugs in Xcode where it crashes itself if you don't do this)
re-open xcode
drag/drop the .h and .m back into Xcode
wait a few seconds (some of Xcode's core methods are asynchronous - allowing it to corrupt your project)
finally, when it seems to be doing nothing (and your hard disk isn't making any noise any more): cmd-b to re-build
I have a 100% success rate with this method. I just tried refactoring with Apple's "Refactor -> Rename" in latest xcode and it failed - again!
(this time with the incorrect error: "Unable to determine the language of", one of those error messages where Apple put the wrong text in place)
I'm going to my project at finder, then change files name by get info.
After that, at xcode -> Project Navigator I delete the files.
At end, I click right on the class and Add files to ..., and add these files again.
It worked for me.
For me I realized Refactor was disabled because the Xcode project I had opened was referencing a Base SDK that was missing. Edit Project Settings and in the Build tab set the Base SDK to one that you have (like for me this was iOS 4.2). This enabled Refactor for me.
Also, it could happen that you renamed the filename for the class, either outside xcode or by ctrl-clicking the filename and then renaming it.
xcode refuses to refactor if filename does not match with the class name.
Go to your class' header file and find the line that looks similar to this:
#interface YourClassName
Right click on the class symbol (e.g. YourClassName) and you should be able to select Refactor -> Rename...
I just tried this and it works in Xcode 5.
This may be a bit late, but I stumbled across this post because I was unable to refactor my "ViewController.swift" file to "WhateverViewController.swift". I tried selecting the file in the Project Navigator and then selecting "Editor -> Refactor" from the top menu, but 'rename' is always greyed out.
Instead, what worked was selecting the ViewController name from the editor. So if you have:
class ViewController: UIViewController {
// Code here...
}
Highlight the "ViewController" word and then select Refactor from the menu or right-click and select Refactor -> rename.
Hopefully that helps...
Had this problem as well. I ran through trying to find missing SDKs, saving files, and looking for Objective-C++ code as mentioned above, and all it took to fix my machine was rebooting XCode.
Seems a little buggy still.
BTW, this was for XCode 4.0.1
Refactoring works If you first change the file name in the project navigator.