'String' does not conform to protocol 'CollectionType' Error in Swift 2.0 - error-handling

I just downloaded XCode Beta 7 and received the error "Type 'String' does not conform to protocol 'CollectionType'". This is my first attempt at coding, so I'm not sure how to fix this. Thank you!!!
//the Pasteboard is nil if full access is not granted
let pbWrapped: UIPasteboard? = UIPasteboard.generalPasteboard()
if let pb = pbWrapped {
var type = UIPasteboardTypeListImage[0] as! String
if (count(type) > 0) && (image != nil) {
pb.setData(UIImagePNGRepresentation(image!)!, forPasteboardType: type)
var readDataWrapped: NSData? = pb.dataForPasteboardType(type)
if let readData = readDataWrapped {
var readImage = UIImage(data: readData, scale: 2)
print("\(image) == \(pb.image) == \(readImage)")
}
}
}

Change it to:
type.characters.count
Your code should then read:
//the Pasteboard is nil if full access is not granted
let pbWrapped: UIPasteboard? = UIPasteboard.generalPasteboard()
if let pb = pbWrapped {
var type = UIPasteboardTypeListImage[0] as! String
if (type.characters.count > 0) && (image != nil) {
pb.setData(UIImagePNGRepresentation(image!)!, forPasteboardType: type)
var readDataWrapped: NSData? = pb.dataForPasteboardType(type)
if let readData = readDataWrapped {
var readImage = UIImage(data: readData, scale: 2)
print("\(image) == \(pb.image) == \(readImage)")
}
}
}

Just a suggestion for where to start learning about this issue... https://developer.apple.com/swift/blog/?id=30
Strings in Swift 2

Related

Picture Storage as URL in SQLite DB in Swift 5

I have a swift project that uses an array of pictures. The array of pictures is kept in storage in the filmanager.default.urls path. The URLs are then kept in a SQLite database. I am able to add to the array without a problem, however, I run into an issue whenever I try to recall it from memory. I do not know if I am saving it wrong or loading it wrong. I will post the code for how I did that here.
func save(images: Array<UIImage>, identifier: String) -> Array<String> {
var picCounter = 0
var URLs: Array<String> = []
for pic in images {
let id = identifier + "makeSureThisCantAccidentallyBeAnID" + String(picCounter)
let jpgImageData = pic.jpegData(compressionQuality: 0.5)
let documentURL = fileManager.urls(for: .documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).first
let path = documentURL!.appendingPathComponent(id + ".png")
do {
try jpgImageData!.write(to: path)
} catch {
print(error)
}
picCounter += 1
URLs.append(path.absoluteString)
}
return URLs
}
That is my save function. It should store the URLs and return an array of URLs in string format.
Here is my loading function, it should take an array of URLs and return the array of images.
func recover(URLarray: Array<String>, identifier: String) -> Array<UIImage> {
if URLarray[0] == "fake url" {
let pic = #imageLiteral(resourceName: "LaunchScreen")
let fakeArray = [pic]
return fakeArray
}
var picCounter = 0
var imageArray: Array<UIImage> = []
for url in URLarray {
//let fileData = FileManager.default.contents(atPath: url)
guard let image = UIImage(contentsOfFile: url) else { return imageArray }
picCounter += 1
imageArray.append(image)
}
return imageArray
}
The "#imageliteral" is a literal image that is used instead of an array if there is no array to load. This should theoretically recall every image without returning nil. Lastly, I will post my SQLite saving function
func saveNote(note: Note) {
connect()
var statement: OpaquePointer? = nil
if sqlite3_prepare_v2(
database,
"UPDATE remember SET person = ?, memories = ?, imageurl = ? WHERE rowid = ?",
-1,
&statement,
nil
) == SQLITE_OK {
sqlite3_bind_text(statement, 1, NSString(string: note.person).utf8String, -1, nil)
sqlite3_bind_text(statement, 2, NSString(string: note.memories).utf8String, -1, nil)
var imageURL: String = ""
for url in note.imageURLs {
imageURL.append(url)
imageURL.append("#")
}
sqlite3_bind_text(statement, 3, NSString(string: imageURL).utf8String, -1, nil)
sqlite3_bind_int(statement, 4, note.id)
if sqlite3_step(statement) != SQLITE_DONE {
print("Error saving note")
}
}
else {
print("Error creating note update statement")
}
sqlite3_finalize(statement)
}
This is how I tried to save it. I had to store a URL array as one string so I decided to do so by making it a string I could split with the character "#" if you think that is the problem then please tell me what character or method I could use to do this, as I have tried changing the character. If anyone helps me this far then I am extremely grateful! Thank you!

Playing WAV data with AVAudioEngine

Currently, I'm getting an EXC_BAD_ACCESS error on the audio thread, and I'm trying to deduce what is going wrong.
When converting .wav file data from Data to an AVAudioPCMBuffer, do I need to strip the RIFF header first?
import AVFoundation
public class Player : NSObject {
let engine = AVAudioEngine()
public override init() {
super.init()
do {
let _ = engine.mainMixerNode
try engine.start()
} catch {
print("Player error: \(error)")
}
}
#objc public func play(_ data: Data) {
let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 48000, channels: 2, interleaved: true)!
let buffer = data.toPCMBuffer(format: format)!
let player = AVAudioPlayerNode()
engine.attach(player)
engine.connect(player, to: engine.mainMixerNode, format: nil)
player.scheduleBuffer(buffer, at: nil, completionCallbackType: .dataPlayedBack) {
callbackType in
// Nothing in here.
}
player.play()
}
}
Here's the toPCMBuffer extension:
// Taken from: https://stackoverflow.com/a/52731480/2228559
extension Data {
func toPCMBuffer(format: AVAudioFormat) -> AVAudioPCMBuffer? {
let streamDesc = format.streamDescription.pointee
let frameCapacity = UInt32(count) / streamDesc.mBytesPerFrame
guard let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: frameCapacity) else { return nil }
buffer.frameLength = buffer.frameCapacity
let audioBuffer = buffer.audioBufferList.pointee.mBuffers
withUnsafeBytes { addr in
audioBuffer.mData?.copyMemory(from: addr, byteCount: Int(audioBuffer.mDataByteSize))
}
return buffer
}
}
Note: I cannot use AVAudioFile because the .wav file data is loaded over-the-wire.
IDK, but my mac crashes if I play interleaved AVAudioPCMBuffers, and garbled audio if they're not float data, so you could convert to non-interleaved float data:
#objc public func play(_ data: Data) {
let sampleRate: Double = 48000
let interleavedFormat = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: sampleRate, channels: 2, interleaved: true)!
let interleavedBuffer = data.toPCMBuffer(format: interleavedFormat)!
let nonInterleavedFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: sampleRate, channels: 2, interleaved: false)!
let nonInterleavedBuffer = AVAudioPCMBuffer(pcmFormat: nonInterleavedFormat, frameCapacity: interleavedBuffer.frameCapacity)!
nonInterleavedBuffer.frameLength = interleavedBuffer.frameLength
let converter = AVAudioConverter(from: interleavedFormat, to: nonInterleavedFormat)!
try! converter.convert(to: nonInterleavedBuffer, from: interleavedBuffer)
let player = AVAudioPlayerNode()
engine.attach(player)
engine.connect(player, to: engine.mainMixerNode, format: nil)
player.scheduleBuffer(nonInterleavedBuffer, at: nil, completionCallbackType: .dataPlayedBack) {
callbackType in
// Nothing in here.
}
player.play()
}
extension Data {
func toPCMBuffer(format: AVAudioFormat) -> AVAudioPCMBuffer? {
assert(format.isInterleaved)
let streamDesc = format.streamDescription.pointee
let frameCapacity = UInt32(count) / streamDesc.mBytesPerFrame
guard let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: frameCapacity) else { return nil }
buffer.frameLength = buffer.frameCapacity
let b = UnsafeMutableBufferPointer(start: buffer.int16ChannelData![0], count: buffer.stride * Int(frameCapacity))
let bytesCopied = self.copyBytes(to: b)
assert(bytesCopied == count)
return buffer
}
}

AVFoundation: Take High Quality Still Image in Video-Session

I am anlysing live-images in a Capture-Session of Type AVMediaTypeVideo. How can I capture a high-quality-still image (not the low-resolution sample buffer), at certain events=
var videoCaptureDevice: AVCaptureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
var device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
var previewLayer: AVCaptureVideoPreviewLayer?
var captureSession = AVCaptureSession()
let cameraOutput = AVCapturePhotoOutput()
//called in view did load
private func setupCamera() {
let input = try? AVCaptureDeviceInput(device: videoCaptureDevice)
captureSession.sessionPreset = AVCaptureSessionPreset640x480
if self.captureSession.canAddInput(input) {
self.captureSession.addInput(input)
}
self.previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
let videoDataOutput = AVCaptureVideoDataOutput()
if self.captureSession.canAddOutput(videoDataOutput){
self.captureSession.addOutput(videoDataOutput)
videoDataOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
}
}
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
// sampleBuffer is analysed
// if result is positive, I would like to take a high quality picture
}
Here's a little snippet that I use in my apps. I hope this will be helpful
private func takePhoto() -> Void
{
if let videoConnection = stillImageOutput!.connection(withMediaType: AVMediaTypeVideo)
{
videoConnection.videoOrientation = AVCaptureVideoOrientation.portrait
stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (sampleBuffer, error) in
guard let buffer = sampleBuffer else
{
return
}
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(buffer)
let dataProvider = CGDataProvider(data: imageData as! CFData)
let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!,
decode: nil,
shouldInterpolate: true,
intent: CGColorRenderingIntent.defaultIntent)
// The image taked
let image: UIImage = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: UIImageOrientation.right)
// Detenemos la captura de imagenes
self.captureSession!.stopRunning()
})
}
}
If you don't set the sessionPreset property of your captureSession variable, by default his values is AVCapture​Session​Preset​High. The only preset that is higher than this is AVCaptureSessionPresetPhoto

iOS - Realm Query is not working properly

I am using Swift(2.2) Realm Framework as doing with document. Here is my codes.
class SwipedAsset: Object{
dynamic var identifier = ""
dynamic var createdAt = ""
}
// save data
let realm = try! Realm()
let fileName = asset.originalFilename
if fileName != nil {
let swipedAssets = realm.objects(SwipedAsset.self).filter("identifier == '\(fileName!)'")
let assetCount = swipedAssets.count
if assetCount == 0 {
let swipedAsset = SwipedAsset()
if asset.originalFilename != nil {
swipedAsset.identifier = asset.originalFilename!
}
if asset.creationDate != nil {
let year = String(asset.creationDate!.year)[2...3]
let key = "\(asset.creationDate!.monthName) \(year)"
swipedAsset.createdAt = key
}
let realm = try! Realm()
try! realm.write{
realm.add(swipedAsset)
}
}
}
// load data
let realm = try! Realm()
let swipedAssets = realm.objects(SwipedAsset.self).filter("createdAt == '\(key)'")
let lastObject = swipedAssets.last
print(lastObject.identifier)
print(lastObject.createdAt)
Here, values are all "", "" Nothing, But swipedAssets.count = 3 I thought it means realm's query is working properly.
What's wrong with me ? Thanks for any help.
Please do not try to debug with breakpoint.

Accessing temp directory in Swift

I was trying to access temp directory in Swift. In Objective-C, I could use the following code to do so:
- (NSString *)tempDirectory {
NSString *tempDirectoryTemplate =
[NSTemporaryDirectory() stringByAppendingPathComponent:#"XXXXX"];
const char *tempDirectoryTemplateCString = [tempDirectoryTemplate fileSystemRepresentation];
char *tempDirectoryNameCString = (char *)malloc(strlen(tempDirectoryTemplateCString) + 1);
strcpy(tempDirectoryNameCString, tempDirectoryTemplateCString);
char *result = mkdtemp(tempDirectoryNameCString);
if (!result) {
return nil;
}
NSString *tempDirectoryPath = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempDirectoryNameCString length:strlen(result)];
free(tempDirectoryNameCString);
return tempDirectoryPath;
}
However, I'm a bit confuse about the type conversion and casting from Objective-C to Swift, such as const char * or CMutablePointer<CChar>. Is there any documents that I should look into?
Thanks.
How about something like :
public extension FileManager {
func createTempDirectory() throws -> String {
let tempDirectory = (NSTemporaryDirectory() as NSString).appendingPathComponent(UUID().uuidString)
try FileManager.default.createDirectory(atPath: tempDirectory,
withIntermediateDirectories: true,
attributes: nil)
return tempDirectory
}
}
It doesn't answer your question about char* but it's cleaner...
NSFileManager reference here.
Also check out this SO question regarding unique names.
According to Apple, use of NSTemporaryDirectory is discouraged:
See the FileManager method url(for:in:appropriateFor:create:) for the
preferred means of finding the correct temporary directory. For more
information about temporary files, see File System Programming Guide.
So instead, you should use FileManager.default.temporaryDirectory
or if you want an unique path:
let extractionPath = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
Swift 2.1 version:
func createTempDirectory() -> String? {
let tempDirURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent("XXXXXX")
do {
try NSFileManager.defaultManager().createDirectoryAtURL(tempDirURL, withIntermediateDirectories: true, attributes: nil)
} catch {
return nil
}
return tempDirURL.absoluteString
}
Swift 3 and up
I think a good way to do this in swift is with an extension on FileManager. This should create a unique temporary folder and return the URL to you.
extension FileManager{
func createTemporaryDirectory() throws -> URL {
let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
try createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
return url
}
}
Swift 3 version
func createTempDirectory() -> String? {
guard let tempDirURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("myTempFile.xxx") else {
return nil
}
do {
try FileManager.default.createDirectory(at: tempDirURL, withIntermediateDirectories: true, attributes: nil)
} catch {
return nil
}
return tempDirURL.absoluteString
}
A direct translation of your Objective-C code to Swift would be:
func tempDirectory()->String! {
let tempDirectoryTemplate = NSTemporaryDirectory() + "XXXXX"
var tempDirectoryTemplateCString = tempDirectoryTemplate.fileSystemRepresentation().copy()
let result : CString = reinterpretCast(mkdtemp(&tempDirectoryTemplateCString))
if !result {
return nil
}
let fm = NSFileManager.defaultManager()
let tempDirectoryPath = fm.stringWithFileSystemRepresentation(result, length: Int(strlen(result)))
return tempDirectoryPath
}
It uses the same mkdtemp() BSD method as your original code. This method creates
a directory name from the template which is guaranteed not to exist at the time where
the method is called.
Thanks to Nate Cook who figured out that reinterpretCast() can be used to treat the UnsafePointer<CChar> returned by mkdtemp() as a CString, so that it can be passed to stringWithFileSystemRepresentation(), see Working with C strings in Swift, or: How to convert UnsafePointer<CChar> to CString.
As of Xcode 6 beta 6, the reinterpretCast() is not necessary anymore and the
above code can be simplified to
func tempDirectory()->String! {
let tempDirectoryTemplate = NSTemporaryDirectory() + "XXXXX"
var tempDirectoryTemplateCString = tempDirectoryTemplate.fileSystemRepresentation()
let result = mkdtemp(&tempDirectoryTemplateCString)
if result == nil {
return nil
}
let fm = NSFileManager.defaultManager()
let tempDirectoryPath = fm.stringWithFileSystemRepresentation(result, length: Int(strlen(result)))
return tempDirectoryPath
}