Date   

Re: bonjour broken in iOS 14

 



On Sep 18, 2020, at 2:34 AM, Gerriet M. Denkmann <gerriet@...> wrote:

But in iOS 14 the stateUpdateHandler  gets a .failed NWBrowser.State, with DNS Service Error: NoAuth(-65555)

I'm guessing your network environment includes a DNS server that supports DNS updates (i.e. wide-area Bonjour) but you don't have the credentials to push updates to the DNS server.

This error probably only applies to the browser registration for that domain, not for the local-network domain. I.e. your app should still be working for local network browsing.

If you only want to do local-network (mDNS) browsing, then use `domain: "local"` instead of `domain: nil`.

—Jens

Disclaimer: I've never used the "NW" classes, I'm just working off my knowledge of Bonjour.


bonjour broken in iOS 14

Gerriet M. Denkmann
 

This worked up to iOS 13:

let serviceType = "_Gmd-BackGround._tcp."
let parameters = NWParameters()
parameters.includePeerToPeer = true
let browser = NWBrowser(for: .bonjour(type: serviceType, domain: nil), using: parameters )
browser.stateUpdateHandler =
{ (newState: NWBrowser.State) in

print(“\newState”)
}
browser.start(queue: queue)

But in iOS 14 the stateUpdateHandler gets a .failed NWBrowser.State, with DNS Service Error: NoAuth(-65555)

How can this be fixed?

Gerriet.


Re: custom table row selection highlights - my bug or Apple's?

James Walker
 

On Sep 15, 2020, at 3:05 PM, Alex Zavatone via groups.io <zav=mac.com@groups.io> wrote:

Can you set the background to needsRefresh?
I assume you mean needsDisplay. In my tableViewSelectionDidChange: delegate method, if instead of setting needsDisplay on the table, I say

[self.table enumerateAvailableRowViewsUsingBlock:
^(__kindof NSTableRowView * _Nonnull rowView, NSInteger row)
{
rowView.needsDisplay = YES;
}];

then it does show my highlights. Seems a little baroque, but it works, so thanks!



On Sep 15, 2020, at 4:54 PM, James Walker <list2@jwwalker.com> wrote:

I have a view-based NSTableView in a scroll view. I want to customized the way that selection highlighting is drawn. So, I set up a controller as a delegate of the table, and in the delegate method tableView:rowViewForRow: I provide an instance of a subclass of NSTableRowView, call it NameRowView. NameRowView overrides one method:

- (void) drawBackgroundInRect: (NSRect) dirtyRect
{
NSLog(@"drawBackgroundInRect %@", self);
if (self.selected)
{
[NSColor.greenColor setFill];
}
else
{
[NSColor.yellowColor setFill];
}
NSRectFill( self.bounds );
}

The table delegate also overrides tableViewSelectionDidChange: to call setNeedsDisplay on the table. Now, if I click or use arrow keys, tableViewSelectionDidChange: does get called, but my drawBackgroundInRect: is not called.

However, if I make the window containing the table change its “main” status, then some drawBackgroundInRect: calls finally happen.

And here’s the really weird part: If I create a WindowRef for the window containing the table, like

[self.window windowRef];

then from then on I see the selection highlight changes immediately.






Re: custom table row selection highlights - my bug or Apple's?

Alex Zavatone
 

Can you set the background to needsRefresh?

On Sep 15, 2020, at 4:54 PM, James Walker <list2@jwwalker.com> wrote:

I have a view-based NSTableView in a scroll view. I want to customized the way that selection highlighting is drawn. So, I set up a controller as a delegate of the table, and in the delegate method tableView:rowViewForRow: I provide an instance of a subclass of NSTableRowView, call it NameRowView. NameRowView overrides one method:

- (void) drawBackgroundInRect: (NSRect) dirtyRect
{
NSLog(@"drawBackgroundInRect %@", self);
if (self.selected)
{
[NSColor.greenColor setFill];
}
else
{
[NSColor.yellowColor setFill];
}
NSRectFill( self.bounds );
}

The table delegate also overrides tableViewSelectionDidChange: to call setNeedsDisplay on the table. Now, if I click or use arrow keys, tableViewSelectionDidChange: does get called, but my drawBackgroundInRect: is not called.

However, if I make the window containing the table change its “main” status, then some drawBackgroundInRect: calls finally happen.

And here’s the really weird part: If I create a WindowRef for the window containing the table, like

[self.window windowRef];

then from then on I see the selection highlight changes immediately.


custom table row selection highlights - my bug or Apple's?

James Walker
 

I have a view-based NSTableView in a scroll view. I want to customized the way that selection highlighting is drawn. So, I set up a controller as a delegate of the table, and in the delegate method tableView:rowViewForRow: I provide an instance of a subclass of NSTableRowView, call it NameRowView. NameRowView overrides one method:

- (void) drawBackgroundInRect: (NSRect) dirtyRect
{
NSLog(@"drawBackgroundInRect %@", self);
if (self.selected)
{
[NSColor.greenColor setFill];
}
else
{
[NSColor.yellowColor setFill];
}
NSRectFill( self.bounds );
}

The table delegate also overrides tableViewSelectionDidChange: to call setNeedsDisplay on the table. Now, if I click or use arrow keys, tableViewSelectionDidChange: does get called, but my drawBackgroundInRect: is not called.

However, if I make the window containing the table change its “main” status, then some drawBackgroundInRect: calls finally happen.

And here’s the really weird part: If I create a WindowRef for the window containing the table, like

[self.window windowRef];

then from then on I see the selection highlight changes immediately.


Re: Anyone using CloudKit?

 



On Sep 1, 2020, at 10:38 AM, Jens Alfke <jens@...> wrote:

#2: How the heck does one write tests for CloudKit? … The only real solution I can imagine is to mock the entire CK API, which is feasible since it seems to be implemented in Obj-C, but that would be a big effort and you'd have to reproduce all the behaviors of the real system, which aren't documented.

I've made some progress on mocking by defining a protocol containing the CKDatabase methods I call; an empty extension to mark CKDatabase as implementing that protocol; and a mock class that implements the protocol. Then in my code I just change references to `CKDatabase` to `IndirectCKDatabase`, and allow the instance to be injected.

public protocol IndirectCKDatabase : AnyObject {
    var databaseScope: CKDatabase.Scope { get }
    func add(_ operation: CKDatabaseOperation)
    func save(_ record: CKRecord, completionHandler: @escaping (CKRecord?, Error?) -> Void)
    func delete(withRecordID recordID: CKRecord.ID, completionHandler: @escaping (CKRecord.ID?, Error?) -> Void)
}

extension CKDatabase : IndirectCKDatabase}

class MockCKDatabase : IndirectCKDatabase {
    ...
}

But in implementing the mock class I'm running into roadblocks:
  • The implementation of `add` needs to add metadata (dates, changeTag) to the CKRecord. But there's no way to create this metadata. The properties have no setters, and the only way to instantiate a record with metadata is to pass in an archived copy of the metadata, which can only be produced from a CKRecord that already has it…
  • Various operations need to return CKServerChangeToken instances. There's no way to create these at all, the class has no constructor.

I've been searching for other people's solutions to mocking, and it seems various people have gone down this road, but I haven't found anyone whose gotten farther than I have :(

—Jens


Re: Anyone using CloudKit?

Bill Pitcher
 

when I was working on CloudKit I made a separate User account on my Mac with my developer Apple ID, iCloud enabled, then you can see and test the Cloud data using the browser interface.

I found it straight forward once I realised this.

cheers
Bill

On 2 Sep 2020, at 3:38 am, Jens Alfke <jens@mooseyard.com> wrote:

Hey, is anyone here using CloudKit? I'm getting started with it and have issues. There's some content on Apple's dev forums, but frankly even the new improved forums have awful UX (why couldn't they have simply used Discourse?)

#1: My Apple developer account is not the same as my regular Apple ID. That means the records my app creates are associated with my regular ID, so when I go to the CloudKit Dashboard I can't look inside the private database because I'm signed in with a different ID.

#2: How the heck does one write tests for CloudKit? The server-side environment is super test-unfriendly since there's no way to programmatically set up a clean slate. The only way to get a fresh empty database is to go to the Dashboard and manually press a button to nuke the entire dev container. The only real solution I can imagine is to mock the entire CK API, which is feasible since it seems to be implemented in Obj-C, but that would be a big effort and you'd have to reproduce all the behaviors of the real system, which aren't documented.

—Jens

PS: Cross-posted to the Apple cocoa-dev list; sorry for the duplication.


Re: Anyone using CloudKit?

Alex Zavatone
 

A specific test zone, perhaps when running in the test configuration?

Do you have a helper that can detect the build configuration used to run your app?  I posted some a while ago and can repost if you want.

I’m sure you already have this though.

- Alex Zavatone

On Sep 1, 2020, at 4:32 PM, Jens Alfke <jens@...> wrote:



On Sep 1, 2020, at 10:38 AM, Jens Alfke <jens@...> wrote:

#2: How the heck does one write tests for CloudKit? The server-side environment is super test-unfriendly since there's no way to programmatically set up a clean slate.

I've come up with a solution for this: I can't erase containers/databases, but I can erase a zone by sending a delete followed by a create. That's fine for my purposes because all my code so far operates on a single zone. I just have to start each test with an erase, and make sure tests don't run concurrently. 

To scale this to multiple developers/devices/bots, I'd need to come up with a unique zone name for each device's tests.

—Jens


Re: Anyone using CloudKit?

 



On Sep 1, 2020, at 10:38 AM, Jens Alfke <jens@...> wrote:

#2: How the heck does one write tests for CloudKit? The server-side environment is super test-unfriendly since there's no way to programmatically set up a clean slate.

I've come up with a solution for this: I can't erase containers/databases, but I can erase a zone by sending a delete followed by a create. That's fine for my purposes because all my code so far operates on a single zone. I just have to start each test with an erase, and make sure tests don't run concurrently. 

To scale this to multiple developers/devices/bots, I'd need to come up with a unique zone name for each device's tests.

—Jens


Re: Anyone using CloudKit?

Alex Zavatone
 

I seem to recall that Axel Kee on Twitter completed a project that might be related to this.  He’s in Singapore and is at @soulchildpls on Twitter.

But you know Apple.  It would probably be best to make up a dev account that is only used for testing this.

GL.  I’ll warn/let Axel know that you might be asking him a question.

Cheers,
Alex Zavatone

On Sep 1, 2020, at 12:38 PM, Jens Alfke <jens@...> wrote:

Hey, is anyone here using CloudKit? I'm getting started with it and have issues. There's some content on Apple's dev forums, but frankly even the new improved forums have awful UX (why couldn't they have simply used Discourse?)

#1: My Apple developer account is not the same as my regular Apple ID. That means the records my app creates are associated with my regular ID, so when I go to the CloudKit Dashboard I can't look inside the private database because I'm signed in with a different ID.

#2: How the heck does one write tests for CloudKit? The server-side environment is super test-unfriendly since there's no way to programmatically set up a clean slate. The only way to get a fresh empty database is to go to the Dashboard and manually press a button to nuke the entire dev container. The only real solution I can imagine is to mock the entire CK API, which is feasible since it seems to be implemented in Obj-C, but that would be a big effort and you'd have to reproduce all the behaviors of the real system, which aren't documented.

—Jens

PS: Cross-posted to the Apple cocoa-dev list; sorry for the duplication.




Anyone using CloudKit?

 

Hey, is anyone here using CloudKit? I'm getting started with it and have issues. There's some content on Apple's dev forums, but frankly even the new improved forums have awful UX (why couldn't they have simply used Discourse?)

#1: My Apple developer account is not the same as my regular Apple ID. That means the records my app creates are associated with my regular ID, so when I go to the CloudKit Dashboard I can't look inside the private database because I'm signed in with a different ID.

#2: How the heck does one write tests for CloudKit? The server-side environment is super test-unfriendly since there's no way to programmatically set up a clean slate. The only way to get a fresh empty database is to go to the Dashboard and manually press a button to nuke the entire dev container. The only real solution I can imagine is to mock the entire CK API, which is feasible since it seems to be implemented in Obj-C, but that would be a big effort and you'd have to reproduce all the behaviors of the real system, which aren't documented.

—Jens

PS: Cross-posted to the Apple cocoa-dev list; sorry for the duplication.


Anyone using CloudKit?

 

Hey, is anyone here using CloudKit? I'm getting started with it and have issues. There's some content on Apple's dev forums, but frankly even the new improved forums have awful UX (why couldn't they have simply used Discourse?)

#1: My Apple developer account is not the same as my regular Apple ID. That means the records my app creates are associated with my regular ID, so when I go to the CloudKit Dashboard I can't look inside the private database because I'm signed in with a different ID. 

#2: How the heck does one write tests for CloudKit? The server-side environment is super test-unfriendly since there's no way to programmatically set up a clean slate. The only way to get a fresh empty database is to go to the Dashboard and manually press a button to nuke the entire dev container. The only real solution I can imagine is to mock the entire CK API, which is feasible since it seems to be implemented in Obj-C, but that would be a big effort and you'd have to reproduce all the behaviors of the real system, which aren't documented.

—Jens

PS: I'm about to cross-post this to the other cocoa-dev list at https://apple-dev.groups.io … sorry for the duplication


Re: Design Pattern Help Needed

Alex Zavatone
 

On Aug 28, 2020, at 12:55 PM, Rick Aurbach via groups.io <rlaurb=me.com@groups.io> wrote:

I have what must be a common problem, and am looking for some architectural suggestions.

Over the years, I've built custom objects (e.g., popup calendars, button menus, etc) which have now been added to iOS as of iOS 14. This presents a problem for me, because I want my apps to support pre-14 systems. What I want to implement is:

An @IBDesignable object which implements a custom class on pre-14 systems, but implements the new iOS-14 objects on 14+.
The object must compile and build with a deployment target of 12.0. Obviously this means that I need to use @available and #available to make the link work.
Check Objective-C headers in teh foundation classes. In there, you can see how you can declare a function’s availability to certain OS versions. Once you see how Apple does it in Objective-C, you can also check out the Swift headers and branch to the functions you want to in your wrapper.

Cheers.

Alex Zavatone


Protocols and Default Implementations

Rick Aurbach
 

Suppose I have a protocol that contains a method with a default implementation:
 
    public protocol A {
        func foo()
    }
    
    public extension A {
        func foo() {
            print("A.foo()")
        }
    }
 
Now in a class that conforms to this protocol, I know I can call the method (and get the default implementation) or override the method (and get my own implementation).
 
QUESTION: Is it possible to EXTEND the default implementation. What I'd like to do is write something like:
 
    class X : A {
        func foo() {
            A.foo()
            print("X.foo()")
        }
    }
 
    X.foo() // prints
            // "A.foo()"
            // "X.foo()"
 
This does not, of course, compile. But you can see what I want to do.

Is this possible? If so, how? (The alternative seems to be to repeat the default implementation everywhere we customize the method, which is a real mess if we ever change the content of the default implementation.)
 


Design Pattern Help Needed

Rick Aurbach
 

I have what must be a common problem, and am looking for some architectural suggestions.
 
Over the years, I've built custom objects (e.g., popup calendars, button menus, etc) which have now been added to iOS as of iOS 14. This presents a problem for me, because I want my apps to support pre-14 systems. What I want to implement is:
 
> An @IBDesignable object which implements a custom class on pre-14 systems, but implements the new iOS-14 objects on 14+.
 
> The object must compile and build with a deployment target of 12.0. Obviously this means that I need to use @available and #available to make the link work.
 
> I expect to use adaptor (wrapper) patterns to present a common external API that is iOS-version independent.
 
BUT, I can't figure out how to make this happen. I have some thoughts about making the @IBDesignable class a proxy for an implementation class (which is factory-constructed in the proxy's init methods). The implementation object would be intalled as a subview of the proxy object so all UI would go to it. But I'm sure I'm not thinking of all of the potential issues here.
 
Have you done something similar to this? Can you give any help or advice about such an undertaking before I sit down and get mired in code? (Maybe even a design pattern to share?)
 
Any help would be welcome.
 


Automated connecting to a WiFi network.

Alex Zavatone
 

I’m wondering if anyone thinks it’s remotely possible to automatically connect an iOS device to a WiFi network with user permission.

Sort of select a network, wait for a network access over that interface, transmit data and then disconnect.

Does anyone have any idea on this one or know of a place to start looking?

Thanks in advance,
Alex Zavatone


UISplitViewController and iOS14

Rick Aurbach
 

I have a storyboard-based app based on a split-view. I have edited the split view as shown in the attached screenshot.



My goal is to have a single storyboard that will handle both iPhone and iPad targets, running pre-iOS14 and iOS14+ apps. 

This is pretty much working (using the code shown below). But, on iPhone, I want the .primary column to be initially displayed on application launch. Pre-14, I guaranteed this by implementing splitViewController(_:collapseSecondary:onto:). In iOS14, this isn't getting called because the style is not .unspecified. I tried implementing splitViewController(_:topColumnFor:), but it is never called.

Any ideas on how to force the .primary column to be displayed on application launch?

class SplitViewController : UISplitViewControllerUISplitViewControllerDelegate {

override func viewDidLoad() {

super.viewDidLoad()

 

self.delegate = self

 

if #available(iOS 14.0, *) {

if UIDevice.current.userInterfaceIdiom == .phone {

show(.primary)

}

else {

if UIDevice.current.userInterfaceIdiom == .pad {

preferredDisplayMode = .allVisible

}

}

}

// MARK: - Split view

 

func splitViewController(_ svc: UISplitViewController, willChangeTo displayMode: UISplitViewController.DisplayMode) {

if #available(iOS 14.0, *) {

else {

if displayMode != .allVisibleself.viewControllers.count > 1 {

if let detailNavController = self.viewControllers[1asUINavigationController {

detailNavController.topViewController!.navigationItem.leftBarButtonItem = self.displayModeButtonItem

}

}

}

}

 

@available(iOS 14.0, *)

func splitViewConntroller(_ svc: UISplitViewController, topColumnFor CollapsingToProposedTopColoum: UISplitViewController.Column) -> UISplitViewController.Column {

return .primary

}

 

 

func splitViewController(_ splitViewController: UISplitViewController,

                         collapseSecondary secondaryViewController:UIViewController,

                         onto primaryViewController:UIViewController) -> Bool {

return true

}

}

 


Re: CATiledLayer in NSView (Mac) -- how?

Graham Cox
 

OK, I have this problem generally solved.

There’s one more thing I’d like to ask though - when a tile draws to the screen, it is animated. In some cases that’s annoying, like when something you’re drawing changes state, and lies across tile boundaries - one tile can animate before the other producing a momentary visible edge.

I’d like to turn off animation altogether for this, but I can’t see how to do it. Normally, putting a state change inside a [CATransaction begin] and [CATransaction commit] and setting the current transaction’s animation time to 0 works, but since this one is handled automatically, I don’t get a chance to do that.

Any ideas how to suppress animation for CATiledLayer when it draws to the screen?

—Graham

On 24 Jul 2020, at 12:35 pm, Graham Cox <graham@mapdiva.com> wrote:

Does anyone have sample code or just a few hints how to use CATiledLayer in a NSView on Mac?

I’m reasonably au fait with using layers in a view in general, but this one is very minimally documented and doesn’t seem to work in quite the expected way. I’d like my app to work similarly to how Maps works, which I believe uses this class internally.

—Graham





Re: Data structures and user interaction conundrum

Graham Cox
 

Thanks to everyone who chipped in so far — interesting ideas.

The zOrder is in fact a float (CGFloat, so 64 bit), but as Jens points out, it can’t go on indefinitely.

In experimenting with this, it turns out that limiting the reordering to just the objects that are visually intersected is a really, really nice behaviour from the user’s perspective. It means that every operation has a visible effect, rather than appearing to do nothing in the cases where you are reordering relative to an object some distance away. I believe from a usability perspective this is a good solution. I may add “global” reordering as an option, assuming I can find a solution I like. The trie idea is interesting, but possibly overkill for the feature… and tbh, learning enough about tries to implement one correctly is probably going to take more time than I’m willing to spend. Though I notice there is a class in Core Foundation - CFBurstTrie - that might fit the bill (not sure if it has a public interface however, seems it may be something private).

Regarding running out of precision when ’splitting the difference’ when reordering, the reality is that this is an uncommon operation in terms of sheer numbers. It probably comes up moderately frequently, but my feeling is that it would be unlikely to run out of numbers in most cases. Of course that’s not good enough - it means a potential bug in the limit when things don’t work as they should. But occasionally renumbering the whole stack is likely to work to solve that, and that can be done when the model is built or saved. Or Jens’ idea of using strings could work for reordering, but may be too slow to sort on that order for drawing (which is my main priority - drawing has to be fast). With local reordering, zOrder value clashes inevitably do occur, because objects further away are just not considered while the local renumbering is performed. Again, that doesn’t matter too much because nothing critical rests on this (unlike Jens’ To Do list example), the only time it would reveal itself is if the user drags an object across the canvas and it gets occluded by something and they didn’t expect that. But in an interactive drawing environment, I'd suggest that doesn’t especially matter - they can simply reorder as necessary in that new local area to get the visual result they want.


—Graham




On 24 Jul 2020, at 5:11 am, Jens Alfke <jens@...> wrote:



On Jul 22, 2020, at 7:19 PM, Peter Teeson via groups.io <pteeson@...> wrote:

Are the zObjects integers? If so would it help to make them floats? Intial value 3.0; Back one 2.9  or 2.09; Forward one 3.1 or 3.01?

Sadly, this only postpones the problem — you run out of precision after a while. A  64-bit double only has about 52 bits of mantissa, meaning that some sequences of 52 reorders will cause a collision between adjacent Z values.

I've actually seen this exact problem in other domains — usually having to do with distributed algorithms for preserving ordering, as in a collaborative to-do list with offline support. IIRC it also shows up in some P2P distributed hash tables like Chord and Kademlia.

A workable way to do this is to use strings, since you never run out of room. So the initial objects are labeled A, B, C, D… When you need to put an object in between C and D, you label it CM. When something has to go between CM and D, you label it CS. Eventually you have to fit something between CR and CS, so you label it CRM. (In a real implementation you'd probably use bit-strings instead. Which you can also interpret as fractional binary numbers … exactly like your suggestion except using infinite precision instead of floating point.)

The eventual problem is that over time the Z labels get longer and longer. Probably not an issue for a graphics editor? The usual solution is to occasionally renumber everything with short strings, perhaps when saving.

This is probably equivalent to David Young's radix-trie suggestion … the trie is a more complex data structure than a sorted array, but performs better. Sliding a mere 25,000 pointers around in an array shouldn't take a noticeable amount of time, though (it's only 200KB) provided you only do it once per user command. (And actually, I believe NSArray already turns into something more tree-like when the count grows large, to make inserts/deletes faster.)

—Jens


CATiledLayer in NSView (Mac) -- how?

Graham Cox
 

Does anyone have sample code or just a few hints how to use CATiledLayer in a NSView on Mac?

I’m reasonably au fait with using layers in a view in general, but this one is very minimally documented and doesn’t seem to work in quite the expected way. I’d like my app to work similarly to how Maps works, which I believe uses this class internally.

—Graham

81 - 100 of 1378