Swift WkWebView createWebArchiveData confused on return type - wkwebview

I am trying to capture the content displayed in a webview (not the source, which is a bunch of javascripts). I'm hoping wkwebview's createWebArchiveData is the right method.
So, where I am getting confused is what gets returned from the call.
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.createWebArchiveData(completionHandler: { (result) in
})
the docs say result is Result<data, error>. I did a type(of:) on it and the log printed Result<data, error>...thanks Apple...
when I printed result I got:
success(5990802 bytes)
thought maybe it was a tuple, but result.0 threw an error...
Value of type 'Result<Data, Error>' has no member '0'
tried to convert data to string...that didn't work...
tried to unarchive it, that failed as well.
Cannot convert value of type 'Result<Data, Error>' to expected argument type 'Data
so, any help would be appreciated. I need what is displayed on the screen, not the source code (in case I am going about this wrong).

I solved this. The Result object is an enum with two cases success and failure. You would read the value (in this case because it is Data) like so:
webView.createWebArchiveData(completionHandler: { (result) in
//var strResult = String(utf8String: result)
switch result {
case .success(let data):
let str = String(decoding: data, as: UTF8.self)
print(str)
case .failure(let error):
print(error)
}
})

You have get() method that will return data if result is success, less code for sure :)
if let data = try? result.get() {
//do something with data
}

Related

Typescript Array.filter empty return

Problem statement
I've got problem with an object array I would like to get a sub object array from based on a object property. But via the Array.filter(lambda{}) all I get is an empty list.
The object is like:
export interface objectType1 {
someName: number;
someOtherName: string;
}
export interface ObjectType2 {
name: string;
other: string;
ObjectType1: [];
}
The method to get the subArray is:
private getSubArray(toDivied: ObjectType2[], propertyValue: string){
let list: ObjectType2[] = toDivied.filter((row:ObjectType2) => {
row.name === propertyValue
});
return list;
}
Analys
Namely two things been done ensure filter comparing works and that the data is "as expected".
Brekepoints in visual studio code
Via break points in the return and filter compareison I've inspected that the property value exists (by conditions on the break point) and that the "list" which is returned is empty.
I would like to point out that I use a Typescript linter which usally gives warning for the wrong types and undefined variable calls and such so I am quite sure it shouldn't be an syntax problem.
Tested via javascript if it works in chrome console
remove braces inside callback function
private getSubArray(toDivied: ObjectType2[], propertyValue: string){
let list: ObjectType2[] = toDivied.filter((row:ObjectType2) =>
row.name === propertyValue
);
return list;
}

Method return wrong type of value in Groovy

I'm working on a groovy method to look for a custom attribute and return the value if the key is found.
The problem is that the method is returning the type of value instead of the value.
// There is more code before, but its not involved with this issue.
def UUIDca = 'UUID'
String customAttributeValue = grabCustomAttribute(UUIDca, event_work)
appendLogfile("\n\nTest grabCustomAttribute: ${customAttributeValue}\n")
}
// Grab the Custom Message Attribute values by name
String grabCustomAttribute (String findElement, OprEvent event){
appendLogfile("""\nIN grabCustomAttribute\nElement to look: ${findElement}\n""")
def firstItem = true
if (event.customAttributes?.customAttributes?.size()) {
event.customAttributes.customAttributes.each { ca ->
// Define each CMA to catch here
appendLogfile("""\nElement: ${ca.name} - """)
appendLogfile("""Valor: ${ca.value}\n""")
if ("${ca.name}" == findElement) {
String customValue = ca.value
appendLogfile("""Custom Attribute Found\n""")
appendLogfile(customValue)
return customValue
}
}
}
}
appendLogfile is basically a print to a log file :)
This is the output I'm getting.
IN grabCustomAttribute Element to look: UUID
Element: UUID - Valor: c3bb9169-0ca3-4bcf-beb1-f94eda8ebf1a
Custom Attribute Found
c3bb9169-0ca3-4bcf-beb1-f94eda8ebf1a
Test grabCustomAttribute: [com.hp.opr.api.ws.model.event.OprCustomAttribute#940e503a]
Instead of returning the value, it returns the type of object. It's correct, but I'm looking for the value.
I believe the solution is really simple, but I'm very new to Groovy.
Any help will be appreciated.
Thanks.
In this case the return statement is for the closure, not for the method, so your method is actually returning the list that "each" is iterating over
The easiest approach you can take here is to use Groovy find method to find the element you are searching for. Something like this:
String grabCustomAttribute (String findElement, OprEvent event) {
return event.customAttributes.customAttributes?.find { ca -> ca.name == findElement }.value
}

What is the difference between the two err value?

I'm trying to understand golang interface, my problem is that why err2.What undefined.
Here is a simple code. The output indicates that both err and err2 have same type as *main.MyError, but err2 have no field "What", so there must be some difference between err and err2, but I cannot figure out the difference here. I just began learning golang not long before, any help will be greatly appreciated.
package main
import (
"fmt"
"time"
"reflect"
)
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s",
e.When, e.What)
}
func run() error {
return &MyError{
time.Now(),
"it didn't work",
}
}
func main() {
err := &MyError{time.Now(), "Hello"}
fmt.Println(reflect.TypeOf(err))
fmt.Println(err.What)
err2 := run()
fmt.Println(reflect.TypeOf(err2))
fmt.Println(err2.What)
}
expected output:
main.MyError
Hello
main.MyError
it didn't work
actual output:
\# command-line-arguments
./test.go:34:18: err2.What undefined (type error has no field or method What)
The function run() returns a value of type error, which is an interface type. Yes, it wraps a value of concrete type *MyError, but to get access to MyError's fields, you need to use a type assertion:
fmt.Println(err2.(*MyError).What)
Try it on the Go Playground.
Note that a value of error type may contain values of other concrete types, actually any that implements the error interface. If it would contain a value of another type, the above type assertion would result in a runtime panic.
If you're unsure err2 actually holds a value of type *MyError and you want to avoid the runtime panic, you may use the special form of type assertion to get this information and only act if it is so:
if myerror, ok := err2.(*MyError); ok {
fmt.Println(myerror.What) // Here myerror has static type *MyError
} else {
fmt.Println("Some other error:", err2)
}
Try this one on the Go Playground.
I think the interface of error type is let you use Error() method without any detail in the concrete structure. You can check on the Go Playground

It seems that Swift 4 does not support pattern matching tuple of enums

Is this a limitation in Swift 4 pattern matching or am I doing something wrong. I can't understand what the error message is referring to...
enum Event {
case scan
case stopScanning
}
enum State {
case idle
case scanning
}
let tuple: (State, Event) = (State.idle, Event.scan)
switch(tuple) {
case (.idle, .scan): return State.scanning
case (.scan, .stopScanning): return State.idle
default: return state
}
Produces error:
error: pattern cannot match values of type 'State'
case (.scan, .stopScanning): State.idle
~^~~~
(Immediately after writing the question I saw it... thanks SO for being my rubber duck. 🦆 I'm answering my own question in the hopes of saving somebody a little time if they get this error and don't immediately understand what it is saying and land here from google some day.)
The second case needs to have .scanning (State) not .scan (Event)
Following works:
let t: (State, Event) = (state, event)
switch(t) {
case (.idle, .scan): return State.scanning
case (.scanning, .stopScanning): return State.idle
default: return state
}
In retrospect, the Swift compiler was clearly telling me that the second case had incompatible enum value at 1st position in the tuple.

Cannot pass immutable value as inout argument: function call returns immutable value

I forked this project, so I am not as familiar with all of the details: https://github.com/nebs/hello-bluetooth/blob/master/HelloBluetooth/NSData%2BInt8.swift.
This is all part of an extension of NSData that the I am using to send 8-bit values to an Arduino.
func int8Value() -> Int8 {
var value: Int8 = 0
copyBytes(to: &UInt8(value), count: MemoryLayout<Int8>.size) //BUG
return value
}
However, it appears in Swift 3 that this now throws an error in the copyBytes section. Although I have seen some solutions such as passing an address in the parameter, I did not want to risk breaking the remaining parts of the code. Any suggestions on what to do for this?
The original code was incorrect. UInt8(value) generates a new, immutable value which you cannot write to. I assume the old compiler just let you get away with it, but it was never correct.
What they meant to do was to write to the expected type, and then convert the type at the end.
extension Data {
func int8Value() -> Int8 {
var value: UInt8 = 0
copyBytes(to: &value, count: MemoryLayout<UInt8>.size)
return Int8(value)
}
}
That said, I wouldn't do it that way today. Data will coerce its values to whatever type you want automatically, so this way is safer and simpler and very general:
extension Data {
func int8ValueOfFirstByte() -> Int8 {
return withUnsafeBytes{ return $0.pointee }
}
}
Or this way, which is specific to ints (and even simpler):
extension Data {
func int8Value() -> Int8 {
return Int8(bitPattern: self[0])
}
}

Resources