I am working with Xcode 6, and I'm trying to recreate the code demoed during session 401 "What's new in Xcode 6". I've added an image to Images.xcassets (called Sample) and within the playground file I'm trying to access this image, as demoed.
My code is as follows (like the demo):
var sample = UIImage(named: "Sample")
However, I can't get it to work like the demo. Am I missing something?
Look at the iOS Developer Library->Playground Help and search"Resource Files" and you will find the answer
1、Open the .playground
2、Show the Project navigator by selecting View > Navigators > Show Project Navigator.
3、Drag the images to the Resources
Like follow:
Open the .playground file in Finder.
Create a folder called Resources next to it.
Add any images you want to this folder.
In the playground press opt-cmd-1 to open the File Inspector. You should see the playground on the right. If you don't have it selected, press cmd-1 to open the Project Navigator and click on the playground file.
Under 'Resource Path' choose 'Relative To Playground'
Click the folder icon underneath and choose the Resources folder created earlier.
You should now have a bundle that you can use with the standard NSImage(named:"filename_without_extension"):
Note: Because Xcode will frequently overwrite the .playground folder, I recommend using this method so the resources folder isn't getting constantly deleted and re-created.
I had some trouble with this also.
Unfortunately, Chris' answer didn't work for me. I suspect perhaps a later beta release of Xcode 6 may have removed this setting.
Here's a solution as of Xcode 6.0 beta 4 (6A267N) available 21st July 2014. I would guess that this corresponds to the "Inside playground" option previously. That is where the Resources folder is within the playground package itself.
Here's how to set this up.
Using Finder - or if you're like me and use the awesome Path Finder - right select and choose Show Package Contents as follows:
That reveals the packages Resources folder:
Copying the image files into that folder will do the business:
let imageNames = ["back-button", "background", "bg_top"]
let images = imageNames.map { UIImage(named: $0) }
For Xcode 9:
Select Resources folder
Right click then "Add files to "Resources""
Use it like:
let image = UIImage(named: "no")
As of Xcode 8 Beta 1, you can use Image Literals to import an image into an Xcode playground:
Start typing image to add an image literal:
Select (or browse for) your image:
See your image inline:
However, I can't get it to work like the demo. Am I missing something?
I'm not sure where you need to put the image to refer to it using only the name, but I got the same code to work by specifying the full path to the image, like:
var sample = UIImage(named: "/Users/my_user_name/Desktop/Image1234.jpg")
Having to use the full path seems more complicated than it should be, but it works and it let me move on to more interesting problems.
You can find out the path of resourcePath using these commands in playground:
var bundle = NSBundle.mainBundle()
var path = bundle.resourcePath
Default for me was:
/Applications/Xcode6-Beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Agents
I had difficulty getting this setup for an iOS playground, as opposed to an OS X playground. Trying to do it using bundles and relative paths makes it more complicated.
If you just want to get your hands on an image quickly, you can also just use absolute file path:
On iOS:
# iOS
let absoluteImagePath = "/absolute/path/to/image.png"
let image = UIImage(contentsOfFile: absoluteImagePath)
And on OS X
# OS X
let absoluteImagePath = "/absolute/path/to/image.png"
let image = NSImage(contentsOfFile: absoluteImagePath)
This is what worked for me on Xcode Version 6.1.1.
Create Playground file under same directory as main storyboard.
Open Utilities pane for Playground file, and click the right arrow in Resource Path section to add your images in that directory.
Test image within Playground file.
On the iOS playground with XCode 6 beta 5 (and probably later) you can see the image inside the bundle:
In the playground press Cmd+Opt+1 and click the arrow under the Resource Path (this will open Finder)
Put your picture to this folder
Access it with either
let img = UIImage(named: "logo.png", inBundle: NSBundle.mainBundle(),
compatibleWithTraitCollection: nil)
or
let path = NSBundle.mainBundle().pathForResource("logo", ofType: "png")
let img = UIImage(contentsOfFile:path)
or in Swift 4:
let path = Bundle.main.path(forResource:"logo", ofType: "png")
let img = NSImage(contentsOfFile:path!)
Using XCode 6.3.1 and running playground in full simulator (iOS) I had to do the following:
Find your .playground file in finder
Right click it -> show package contents
If it doesn't already exist, create a folder named Resources inside the package
Add your image there
Then just instantiate with
let i = UIImage(named: "filename.png")
I have no idea why it is not working the easy way with PDF images.
I had to add this extension to load PDF images into my Playground:
extension UIImage {
static func fromPDF(_ url: URL) -> UIImage? {
var image: UIImage?
guard
let doc = CGPDFDocument(url as CFURL),
let page = doc .page(at: 1)
else { return nil }
let pageRect = page.getBoxRect(.mediaBox)
let renderer = UIGraphicsImageRenderer(size: pageRect.size)
image = renderer.image { ctx in
UIColor.clear.set()
ctx.fill(pageRect)
ctx.cgContext.translateBy(x: 0.0, y: pageRect.size.height)
ctx.cgContext.scaleBy(x: 1.0, y: -1.0)
ctx.cgContext.drawPDFPage(page)
}
return image
}
}
// Given the file "myImage.pdf" was added to your Playground's Resources folder.
let image = UIImage.fromPDF(#fileLiteral(resourceName: "myImage.pdf"))
It is based on this: https://developer.apple.com/forums/thread/90990
Related
I have animation Lottie and i can't run animation with assets. Animation playing but without assets.
I put my assets in this path. Web player nice playing. But in iOS in console print: -[LOTLayerContainer _setImageForAsset:]: Warn: image not found: img_0.png. For all images so.
Swift code:
let animation = LOTAnimationView(name: "data")
animation.frame = self.view.frame
animation.contentMode = .scaleAspectFill
self.view.addSubview(animation)
animation.play()
Path:
for solve this reason it needs to add the json files to copy bundle resources.
check the following and if your json file is not there add it there.
choose project-> choose the aim target -> goto Build Phases -> check Copy Bundle Resources
You need to change
animation = LOTAnimationView(name: "data")
to
animation = AnimationView(name: "data")
My project structure is in such a way that I have 2 projects named as ProjectA and ProjectB. Now for these 2 projects, I have created a framework named as ProjFramework.
I have added common files of these 2 projects inside the framework and then added framework in the projects separately. Till now I am able to access all the files and vars. Now I added the images also in the framework and when I am trying to display them in UI then I am getting an error saying unable to read this .png.
As I know I need to include the framework somehow but I don't know how. Please help me in sharing common images b/w 2 XCode projects.
Thanks in advance.
An alternative to #arunjos007' method is to (a) create a bundle of your images, then (b) retrieve from the bundle.
Let's say you have a Framework called Kernel, and you wish to access two types of files - cikernel and png.
Creating a bundle:
Move all your files/images into a new folder on your desktop. Name it whatever you wish. In my example I named them cikernels and images.
Rename your folders, with a .bundle extension. In my example they became cikernels.bundle and images.bundle. You will see the warning below... choose "Add".
Drag the bundle into your framework project. You can expand the bundle to see the contents. Also, you can add/delete/edit the contents of the bundle.
Retrieving files from the bundle:
I've created two public functions, one to retrieve files and one to retrieve images. They are pretty much the same, except for (a) the return type and (b) error handling. (I probably should add some to the UIImage function - but since I have total control on the code - it's not going to be used by anyone else - it's not critical.)
public func returnImage(_ named:String) -> UIImage {
let myBundle = Bundle.init(identifier: "com.companyName.frameworkName")
let imagePath = (myBundle?.path(forResource: "images", ofType: "bundle"))! + "/" + named
let theImage = UIImage(contentsOfFile: imagePath)
return theImage!
}
public func returnKernel(_ named:String) -> String {
let myBundle = Bundle.init(identifier: "com.companyName.frameworkName")
let kernelPath = (myBundle?.path(forResource: "cikernels", ofType: "bundle"))! + "/" + named + ".cikernel"
do {
return try String(contentsOfFile: kernelPath)
}
catch let error as NSError {
return error.description
}
}
One last note: The identifier is defined in the Framework target's General tab. Typically it's in the form com.companyframework*. Change that line to your's.
Before Building and distributing your framework, you should copy files that need to carry with your framework.
To copy files, Click your framework project target, go to "Build Phases" tab and you can see a section called "Copy Files". Add your files here(See below screenshot)
Then build your framework project, after a successful build your distributable framework will be generated in your Products folder. It will look like YourFrameworkProjectName.framework.
Add this file to other projects which need your framework.
Note: If you just want to run your project by connecting with your framework project, you can be done it by adding build dependency. See StackOverflow question here
Currently building an iMessage app, and would like to experiment with using a database. I have a database that I would like to use in the app, and have included it in my project, and verified the target membership is correct. Using SQLite.Swift.
Whenever I try opening the connection to the database in simulator, I always get an error (unexpected nil) for the path of the database.
I've tried an image file the same way with no avail.
let imagePath = Bundle.main.path(forResource: "db", ofType: ".sqlite")
do {
let db = try Connection(imagePath!, readonly: true)
} catch {
}
I believe the issue is more related to what an iMessage "app" is - which is actually an extension, not a true app. There's no initial VC, thus no real Bundle.main to get to.
One (maybe soon a second) app of mine has a Photo Editing Extension - basically what I always have called a "shell connection" to an Apple app. You really have either a "do nothing" app with a connection to one of their apps, or you have a stand-alone app an share the code with the extension.
My solution for sharing code is to use a Framework target. Yes, a third project. (App, extension, shared code.) I found a technique that I think should work for you - basically, for images, scripts (my apps use .cikernel files) you add them into the framework project and return what you need in a function call.
You may be able to streamline this with a need for a Framework target. YMMV. The basics are this:
Someplace in Xcode you have a "Bundle Identifier". Something like *"com.company.projectname".
Put your files into a folder, maybe on your desktop. Add an extension to this folder called ".bundle". macOS will give you a warning, accept it. All you are really doing is creating your bundle.
Drag this into your Xcode project.
Code to get to this bundle, and the files inside it. (I'm not sure if need a framework here - try to drag this into your "MessagesExtension" target first.
So lets say you have images you wish to share between projects, extensions, whatever. After moving them into a folder called "images", andrenaming the folder with a ".bundle" at the end, and finally dragging it into your Xcode project, you pretty much need to add this function:
public func returnImage(_ named:String) -> UIImage {
let myBundle = Bundle.init(identifier: "com.company.project")
let imagePath = (myBundle?.path(forResource: "images", ofType: "bundle"))! + "/" + named
let theImage = UIImage(contentsOfFile: imagePath)
return theImage!
}
For a text file you want:
public func returnKernel(_ named:String) -> String {
let myBundle = Bundle.init(identifier: "com.company.project")
let kernelPath = (myBundle?.path(forResource: "cikernels", ofType: "bundle"))! + "/" + named + ".cikernel"
do {
return try String(contentsOfFile: kernelPath)
}
catch let error as NSError {
return error.description
}
}
Usage, for an image called "Camera.png" which is part of a bundle called "images.bundle":
let cameraImage = returnImage("Camera")
Since I don't work with SQLite files I don't have the exact code, but I think this should work. Remember to change "com.company.project" to what you have for the bundle identifier.
I can't figure out how to display an image "HappyFace.png" in a WebView when the image is inside the Assets.xcassets folder.
Instead, I'm forced to store the image in the same location (same level) as the Assets.xcassets file and other dot swift files. As long as I store it there, I can refer to it by name:
let htmlString: NSString = "<html><body><img src='HappyFace.png'/></body></html>"
let path: NSString = NSBundle.mainBundle().bundlePath
let baseURL: NSURL = NSURL(fileURLWithPath: path as String)
MyWebView.loadHTMLString(htmlString as String, baseURL: baseURL)
Does anyone know how to access the images in xcassets? Is it even appropriate to store my image there? (It's not an app icon, nor a loading screen image, maybe it doesn't belong under xcassets?).
Snapshot of My File Hierarchy
There is no simple way to do this. You must either store the images outside XCAssets and reference them as you have done, or unpack XCAssets into a local directory.
This question includes a useful summary, and one answer demonstrates how to achieve this using a custom URL protocol.
Im trying to load(and upload) images in my app(by picture path).
This is working in my simulator. everything works there. only when im trying to do this on the iphone itself it won't work and i see just the empty UIImageviews.
The paths are loaded the same as in the simulator. And originate from:
PHImageManager.defaultManager().requestImageDataForAsset(asset, options: nil)
{
imageData,dataUTI,orientation,info in
cell.setString(info["PHImageFileSandboxExtensionTokenKey"] as String,name:dataUTI as String)
}
And the PHImageFileSandboxExtentionTokenKey is split into the data and the url when loading the image.
this results in the simulator as :
/Users/Twizzler/Library/Developer/CoreSimulator/Devices/3E671415-8B83-44DA-870F-19BF2BC11F8F/data/Containers/Data/Application/8872109F-3784-40EB-BEB6-4E9FDABE013D/Documents/1613945_10200645161051698_4122753901212984922_n.jpg
and in the iphone as:
/private/var/mobile/Media/DCIM/102APPLE/IMG_2607.JPG
Im loading the image like this:
let image = UIImage(named: "/private/var/mobile/Media/DCIM/102APPLE/IMG_2607.JPG")
cell.imageView.image = image
in this case i put the image url hardcoded (this is in the final app an array of images)
I don't get an error or stack trace. When placeing a breakpoint im seeing the image information in the same way as the simulator
as suggested by the answer im now trying to load them as follows:
let image = UIImage(contentsOfFile: "/private/var/mobile/Media/DCIM/102APPLE/IMG_2607.JPG")
cell.imageView.image = image
This isn't working and i can't upload the files
That’s not how imageNamed works—as the documentation states, that looks for an image with the given name inside your app’s bundle. Try imageWithContentsOfFile.
Well i fixed it! after some puzzling days im now using this way to access upload and
cell.imageView.image = UIImage(data: array[indexPath.row][0] as NSData)
This shows the image. I can save the NSData in the CoreData and reload the image on this way.
To lighten the load on the system im using this:
cellData.checked = 1
var imageData = UIImageJPEGRepresentation(cell.imageView.image, 1)
self.array.append([imageData,cellData.imageData] )
let myObj : ViewControllerImagePicker = self.parentViewController as ViewControllerImagePicker
let textfield: UILabel = myObj.amountLabel! as UILabel
textfield.text = String(self.array.count )
cell.textLabel.alpha = 1
this code is being called when there is clicked on a cell. by setting the cellData.imageData i can recall the cells (when clicking back to the collection view)
I do not know if the way im doing it is correct or works with more that 10 files because of data usage problems. But in my case with a max of 6 selected pictures it works like a charm
The simulator works completely different than a real device when it comes to files, the app bundle and sandboxing.
For starters the simulator will let you write to and add or change files in your app bundle. iOS running on a real device won't let you do this.
You can't hardcode any paths in your app. Even if it works today or on your device in test mode that doesn't mean it will work on a released version. And even if it does it could stop working on any update. Apple several times has changed where things are stored and the path structure in the phone. And where you are allowed to write.
Make bundle calls to get the path locations of standard folders.
Use the assets library to load images from the photo library, or to save them there.
There are tons of resources and tutorials online on how to do this.