Trying to start some Swift work. I am using
var imageData = UIImageJPEGRepresentation(image, compressionQuality:1.0)
but I get a warning "extraneous argument label 'compressionQuality' in call. I thought that in Swift the secondary parameters were either required or 'allowed' to be labelled, but this won't let me use it at all- fails building if I leave it. Since this is a system function, I can't use the # to require it. But I WOULD like to be able to name as many parameters as possible to make code more readable for myself, I like the ObjC method names, as verbose as they sometimes are.
Is there a way to set a compiler flag to allow extra argument labels?
You can't do like that, because that function doesn't declare any external parameter name. Internal parameter names can only be used within the function that declares them.
In Swift UIImageJPEGRepresentation method is declared as:
func UIImageJPEGRepresentation(_ image: UIImage!,
_ compressionQuality: CGFloat) -> NSData!
Check both parameters, both have internal name only so you can't use:
var imageData = UIImageJPEGRepresentation(image, compressionQuality:1.0)
Change that to:
var imageData = UIImageJPEGRepresentation(image,1.0)
Update Swift 4.2:
In swift 4.2, the above mentioned methods are no longer available. Instead of that you need to use:
// For JPEG
let imageData = image.jpegData(compressionQuality: 1.0)
// For PNG
let imageData = image.pngData()
Refer the API Document for more: Images & PDF
I had a similar problem, but Xcode was complaining about it in one of my funcions.
Turned out to be an extra } in my code, making the subsequent function declarations to be outside my class.
The error message was weird as hell, so I hope it hepls somebody else.
Related
We have a cross platform image processing library and there is a call that returns a CGImageRef as an UnsafeRawPointer which I need to turn into a CGImage. I know the call works as when using it in objective c I can just cast using (CGImageRef) returnedData on the returned data and I get the image. However when trying to use it in our iOS app using Swift 4 I can't seem to cast it without getting an EXC_BREAKPOINT error or a BAD_ACCESS error. I've tried casting using as! CGImage as well as trying pointer.load(as: CGImage.self) and both give me the same result. Am I doing something wrong? is there a better way to pass back an image from C code to swift? I should mention that the same C function takes a CGImageRef as a parameter and passing a CGImage in instead causes no issues whatsoever.
I think it’s a memory management issue. E.g. the CGImageRef that you get is released before you use it. Use “Product" > “Scheme" > "Edit Scheme" menu, select “Run" section, “Diagnostics” tab and enable “Zombie Objects” option. Then run the app. If some object is used after deallocation, you will get a message in the console.
If that’s the case, something like this should fix the issue:
// pointer is your UnsafeRawPointer for CGImageRef
let cgImage = Unmanaged<CGImage>.fromOpaque(pointer).takeRetainedValue()
Better yet, if you can edit or override header files for the library in question, you can annotate C functions to let Swift know how to handle the pointers properly.
I'm having trouble successfully setting local data for Siesta in Swift. My goal is to set a UIImage for a URL locally, so that this local image can be displayed with no download time.
To do this, I'm setting the image data for the URL as such:
let resource = CustomRemoteImageView.imageCache.resource(myPhoto.url.absoluteString)
let imageData = UIImagePNGRepresentation(image)! // I've also tried putting the UIImage directly in there, because the transformation chain doesn't apply to local data, right?
let entity: Entity<Any> = Entity(content: imageData, contentType: "*/*") // I've played around with the content type too!
resource.overrideLocalData(with: entity)
I'm then using a custom Service that always tries to parse content as an Image:
private let imageTransformer =
ResponseContentTransformer
{ Image(data: $0.content)}
convenience init() {
self.init(standardTransformers: [])
configure {
$0.pipeline[PipelineStageKey.parsing].add(self.imageTransformer, contentTypes: ["*/*"])
}
}
This system is working great for all remote images, but it always seems to fail to parse this overridden local image. It seems like it's trying to parse but just fails every time.
i.e. I'm getting a Siesta.ResourceEvent of
(Siesta.ResourceEvent) $R20 = newData {
newData = network
}
but the actual .typedContent is nil.
overrideLocalData and overrideLocalContent do not interact with the pipeline at all. Siesta won’t try to parse what you pass; what you override is what your resource gets.
Furthermore, overrideLocalData and overrideLocalContent don’t fail. They always update the resource’s content. If you call those methods, the resource content will match what you passed.
So … the problem isn’t parsing. What might it be?
Entity.typedContent is a shortcut for applying as? to a resource’s entity’s content. If you're getting nil, it means that either (1) the content of the entity you passed to the overrideLocalData was nil or (2) the contextual type in which you’re calling typedContent doesn’t match the content’s actual runtime type.
What do you see if you print resource.latestData.content? That will show you what’s actually there, and will rule out type conversion issues with typedContent.
If it’s not nil, compare its value from a network request and get the types to match.
If it is nil, then either something else cleared the content or you passed nil content in the first place. Try SiestaLog.Category.enabled = .common and see if you can spot where it is or isn’t getting set to the right thing.
I am currently updating a project to use image literals, to enjoy the benefits of non-optional images. The project is importing various frameworks, and the frameworks are containing images.
In the frameworks, we had to declare an extension on UIImage to override the initialiser, because it was looking for the image in the wrong bundle. We did something like:
extension UIImage {
convenience init?(framework_named imageName: String) {
let bundle = Bundle(for: ClassNameInFramework.self)
self.init(named: imageName, in: bundle, compatibleWith: nil)
}
}
I am wanting to use image literals in the framework too, but like before, the literals are looking for the wrong bundle for the image and the application crashes.
Does anyone know, how to specify the image literal to which bundle to look for the image?
I discovered a pretty simple workaround and was amazed to not find it anywhere on other posts. I wish it could be more elegant, but it's preferable than using the stringly-typed UIImage(named:in:compatibleWith:) initializer in my opinion.
We basically take advantage of the _ExpressibleByImageLiteral protocol, which is what Xcode uses to determine if a type is expressible by an image literal. It's part of the Swift standard library, but it's hidden from autocompletion, I guess because it's uncommon to want to initialize a custom type with an image literal. However, it's just what we want and behaves exactly like the other ExpressibleBy protocols.
struct WrappedBundleImage: _ExpressibleByImageLiteral {
let image: UIImage?
init(imageLiteralResourceName name: String) {
let bundle = Bundle(for: ClassInFramework.self)
image = UIImage(named: name, in: bundle, compatibleWith: nil)
}
}
Note that I use a wrapper instead of a UIImage subclass, which would seem like a better option. Sadly, classes like UIImage are not intended to be subclassed and you will find yourself getting a lot of headaches if you do.
And now its usage becomes:
let image = (🏞 as WrappedBundleImage).image
Not as concise as a normal image literal, but it's the best we've got for now. We just have to remember to do the as casting, otherwise our custom initializer will not get called.
You can also do something like this:
extension UIImage {
static func fromWrappedBundleImage(_ wrappedImage: WrappedBundleImage) -> UIImage? {
return wrappedImage.image
}
}
And we can now use it like this:
UIImage.fromWrappedBundleImage(🏞)
Hope this helps!
I am in the middle of updating my app which was built in ios 8 to ios9 by using xcode7/swift 2.0. Like many other people, my app crashed very heavily. The basic concept of my app is to let users to upload videos/images to a certain event. Right now, I am having an error message saying
object not found for update (Code: 101, Version: 1.9.0)
from parse. I thought it was Parse's error at first but figured out I may have made some dumb mistakes while I was updating codes. If you can take a look at the changes I made and point out the errors I made, it would be super helpful.
I changed following:
var outputURL = NSURL.fileURLWithPath(NSTemporaryDirectory().stringByAppendingPathComponent("\(filename)").stringByAppendingString(".mp4"))
to
var outputURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent("\(filename).mp4")
I made this change because stringByAppendingString is deprecated now.
Other change i made is:
let filename = (outputFileUrl.absoluteString.stringByDeletingPathExtension.lastPathComponent ?? "video") + "-c"
to
let filename = (outputFileUrl.URLByDeletingPathExtension?.lastPathComponent ?? "video") + "-c"
I am pretty sure I did right with converting functions. It would be greatly appreciated if anyone can point out what I did wrong in those two changes.
The difference of the first example is:
The former syntax creates an NSString object
The new syntax creates an NSURL object
Either use the URL related API for example instead of …contentsOfFile use …contentsOfURL or get the path of the URL from the path property
let outputURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent("\(filename).mp4").path!
The second example returns a string with percent encoded special characters in the former syntax and a string without percent encoding in the new syntax. You might add the percent encoding.
An alternative method to keep the older syntax is to cast the String to NSString e.g.
let filename = (((outputFileUrl.absoluteString as NSString).stringByDeletingPathExtension as NSString).lastPathComponent ?? "video") + "-c"
but I recommend to use the URL related API
I've been trying to create an archive using the ZipZap library (https://github.com/pixelglow/zipzap) and to be more specific the 8.0 release. The library is consumed in Swift code.
I've read that when calling:
newArchive.updateEntries(archiveItems, error: error)
Requires the "archiveItems" to be NSMutableArray and it is defined as such. At this point I tried creating an archive that contains just one directory so the array looks like:
var archiveItems = NSMutableArray()
archiveItems.addObject(ZZArchiveEntry(directoryName: "\(archiveName)/"))
"newArchive" is created the following way:
var newArchive = ZZArchive(URL: NSURL(fileURLWithPath: archivePath), error: error)
The error I see is: EXC_BREAKPOINT(code=1, subcode=0x1001bc998)
And I've also seen: EXC_BREAKPOINT(code=1, subcode=0x100100998)
In case I do not call the updateEntries method the code does not crash. So my assumption is that the crash happens inside this method.
At the end it was me not reading the spec as it is written in the example on GitHub.
After a help from Glen Low (pixelglow) the issue was that I am actually trying to create a new file without sending an option to create the file in case it does not exist.
So a massive thanks goes to pixelglow for his help and the great library!
The proper way to call the init when you need to create the file is:
var newArchive = ZZArchive(URL: NSURL(fileURLWithPath: archivePath), options: [ZZOpenOptionsCreateIfMissingKey: true], error: &archiveError)