我真的不熟悉macOS的开发,并试图找出正确的方法来进行此操作。场景:我的应用程序使用加密的文档。这些是跨平台的,因此我无法更改加密机制(例如,直接使用OS提供的功能)。我还想稍后创建一个iOS应用,并共享尽可能多的代码。
流程应为:
所以我有这些课程:
所有内容都包含在一个main.storyboard中(考虑拆分,但首先要弄清楚正确的体系结构):
我在read(from data: Data, ofType typeName: String)
中实现了MyEncryptedDocument
,只是将内容读取为字节数组。现在,在这里我将显示密码提示,但是看来NSDocument类不是正确的位置-对于初学者,我没有WindowController,并且windowControllers
为空(我假设之后会调用makeWindowControllers。)
我一直在考虑将NSWindowController或NSWindow子类化,但是然后我想知道密码提示的正确位置在哪里?尽管我可以通过awakeFromNib
进行分配,但WindowController中的makeWindowControllers
还没有文档。
这让我有以下问题:
MyEncryptedDocument
应该只处理二进制的加密数据吗?还是应该处理密码和解密的业务对象?我对Swift或Objective-C都很满意,因为我更关心“ Where”,而不关心确切的“ How”。
答案 0 :(得分:1)
这是我现在实现的方式:
makeUntitledDocumentOfType:error:
和makeDocumentWithContentsOfURL:ofType:error:
设置处理程序readFromData:ofType:error:
和dataOfType:error:
中使用它来加载/解密以及保存/加密数据在我看来,DocumentController确实似乎是应该处理此问题的地方,因为密码/加密更像是管道问题,而不是实际文档或任何UI。总的来说,这对我来说是经验不足的macOS开发人员。我不确定NSAlert是否是对话框的正确类;看Apple's Guidelines,我认为我应该创建自己的NSPanel或NSWindow。但这是以后要担心的。
在Xamarin C#代码中,该类如下所示:
public class MyEncryptedDocumentController : NSDocumentController
{
public MyEncryptedDocumentController()
{
}
// makeUntitledDocumentOfType:error:
public override NSObject MakeUntitledDocument(string typeName, out NSError error)
{
return LoadOrCreateDocument(typeName, null, out error);
}
// makeDocumentWithContentsOfURL:ofType:error:
public override NSObject MakeDocument(NSUrl url, string typeName, out NSError outError)
{
return LoadOrCreateDocument(typeName, url, out outError);
}
private MyEncryptedDocument LoadOrCreateDocument(string typeName, NSUrl url, out NSError error)
{
error = null;
using (var sb = NSStoryboard.FromName("PasswordView", null))
using (var ctrl = sb.InstantiateControllerWithIdentifier("Password View Controller") as PasswordViewController)
using (var win = new NSAlert())
{
win.MessageText = "Please enter the Password:";
//win.InformativeText = "Error message goes here.";
win.AlertStyle = NSAlertStyle.Informational;
win.AccessoryView = ctrl.View;
var btnOK = win.AddButton("OK");
var btnCancel = win.AddButton("Cancel");
var res = win.RunModal();
var pw = ctrl.Password;
if (res == (int)NSAlertButtonReturn.First)
{
var doc = new MyEncryptedDocument(pw);
if (url != null)
{
if (!doc.ReadFromUrl(url, typeName, out error))
{
// Could check if error is a custom "Wrong Password"
// and then re-open the Alert, setting the Informational Text
// to something like "wrong password"
return null;
}
}
return doc;
}
// MyEncryptedDocument.Domain is a NSString("com.mycompany.myapplication");
// MyErrorCodes is just a custom c# enum
error = new NSError(MyEncryptedDocument.Domain, (int)MyErrorCodes.PasswordDialogCancel);
return null;
}
}
}
PasswordViewController
是NSViewController的一个非常简单的子类:
public partial class PasswordViewController : NSViewController
{
public string Password { get => tbPassphrase?.StringValue ?? ""; }
public PasswordViewController(IntPtr handle) : base(handle)
{
}
}
tbPassphrase
是视图中文本框的出口(.h文件中的@synthesize tbPassphrase = _tbPassphrase;
)。故事板是带有viewController的简单场景:
<viewController storyboardIdentifier="Password View Controller" id="5LL-3u-LyJ" customClass="PasswordViewController" sceneMemberID="viewController">
<view key="view" id="yoi-7p-9v6">
<rect key="frame" x="0.0" y="0.0" width="315" height="22"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<secureTextField identifier="tfPassphrase" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="YmM-nK-9Hb">
<rect key="frame" x="0.0" y="0.0" width="315" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" usesSingleLineMode="YES" id="ChX-i5-luo">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<allowedInputSourceLocales>
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
</allowedInputSourceLocales>
</secureTextFieldCell>
</secureTextField>
</subviews>
</view>
<connections>
<outlet property="tbPassphrase" destination="YmM-nK-9Hb" id="sCC-Ve-8FO"/>
</connections>
</viewController>